在上一篇文章中,我们简单学习了如何用scrapy框架对豆瓣top250电影进行简单的爬虫。
但上一篇文章中还只是进行了最基本的数据爬取,本篇文章会针对以下两种情况,介绍常用的解决方法
- 需要登陆鉴权
- 爬取的内容是通过js动态渲染的
js动态渲染
首先还是和上一篇文章一样,搭一个初始的scrapy框架
scrapy startproject spider_test
创建一个login item
scrapy genspider LoginItem "https://bbs.gter.net/thread-XXXXX.html"
这次我们来尝试一下爬取寄托天下论坛的一篇帖子(仅做学习使用,不要用于其他用途),上面的url换成你想爬的网站。
比如我们要爬取这个通知时间,可是需要登陆后才能查看
登陆鉴权我们下一节再介绍,如果我们用postman去post这个url
可以看到实际上它的内容和F12看到的是不一样的
我们先尝试一下根据xpath强行爬取一下是什么结果
修改LoginItem.py 如下(记得修改url)
class LoginItemSpider(scrapy.Spider):
name = 'login'
allowed_domains = [' ']
start_urls = ['https://bbs.gter.net/thread-XXXXX.html']
spider_url = []
def start_requests(self):
yield scrapy.Request(url=self.start_urls[0], callback=self.parse)
def parse(self, response):
time = response.xpath(
'//html/body/div[7]/div[5]/div[2]/div[1]/div/div/table/tbody/tr[1]/td[2]/div[2]/div/div[1]/div/table[1]/tbody/tr[8]/td/a/text()').extract_first()
print("res:", time)
爬出来的结果是None,原因是这部分内容是通过js异步渲染的,我们拿到的html是没有这个内容的
要解决这个问题,需要用scrapy-splash这个框架来先进行渲染,然后再爬取.
splash是一个JavaScript渲染服务。它是一个实现了HTTP API的轻量级浏览器,splash使用python实现的,同时使用Twisted和QT.
docker安装和部署
docker run -p 8050:8050 scrapinghub/splash
浏览器输入http://localhost:8050/ 如果界面如下则启动成功
在setting.py中添加如下配置
ROBOTSTXT_OBEY = False
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
# 去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
# 使用Splash的Http缓存
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
useragent是用于反爬虫的,DOWNLOADER_MIDDLEWARES设置了不同中间件的优先级,SPLASH_URL是splash部署的端口地址。
更详细的使用说明可以参考教程
配置好后,既可以使用splash来渲染页面然后再爬取,需要将scrapy.Request更换为SplashRequest
from scrapy_splash import SplashRequest
此时在执行
scrapy crawl login
可以看到成功爬取到渲染后的数据
登陆鉴权
这篇文章介绍了常见的登陆鉴权和爬虫模拟登陆的方式。
在前面一节我们已经成功得到了渲染后的页面数据,但有些数据需要登陆后才能获得。
这里我们简单介绍一下Cookie结合scrapy框架模拟登陆的方法. setting.py中增加以下配置
COOKIES_ENABLED = True
F12登陆账户后获取你的cookie信息
def start_requests(self):
cookiestr = "你的cookie"
cookies = {i.split("=")[0]: i.split("=")[1] for i in cookiestr.split("; ")}
yield SplashRequest(url=self.start_urls[0], cookies=cookies,callback=self.parse)
def parse(self, response):
time = response.xpath(
'///html/body/div[3]/div/div/div[1]/strong/a/text()').extract_first()
print("res:", time)
先换个xpath获取一下用户名
可以看到获取成功了,这种方式可以用来模拟登陆。
但是在获取上一节通知时间的数据时,虽然模拟成功,但由于它是利用ajax异步去post另一个页面获取数据的,那个post并没有带上我们发过去的cookie,所以没能获取到数据,但可以直接利用cookie访问图上这个url获取数据。
这个图可以看到我们的cookie是让我么模拟登陆成功了的,但是没能拿到异步获取的数据。
至于怎么才能让页面异步获取时也带上我们这个cookie,还需要再深入看一下,有懂的大佬可以评论区教一下