想想大家也清楚,一个爬虫最基础的防反扒机制是动态设置User-Agent(以下简称UA),在scrapy中有几个与随机User-Agent相关的设置,我今天来跟大家交流交流这几个方面。
探索
仔细研究就会发现,scrapy 中有很多默认中间件,每个请求都会经过这些中间件,但它们的启动会遵循一定的顺序,而不是同时启动,以下是这些默认中间件:
DOWNLOADER_MIDDLEWARES_BASE={
? ?'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
? ?'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
? ?'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
? ?'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
? ?'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
? ?'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
? ?'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
? ?'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
? ?'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
? ?'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
? ?'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
? ?'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
? ?'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
? ?'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}
这些默认中间件会在项目运行中和你在settings.py中设置的DOWNLOADER_MIDDLEWARES 进行合并,以下是该参数:
DOWNLOADER_MIDDLEWARES = {
? ?'baidu.middlewares.bdUserAgentMiddleware': 520,
}
每个中间件的后面都有个整数值,整数值的大小决定了他们的调用顺序,每个中间件的 process_request() 将会根据数值从小到大依次调用,而process_response() 将会反向调用,由此可知scrapy调用中间件的方式是使用栈数据结构,也就是LIFO的模式。
你可以自己写入自己的UserAgentMiddleware 中间件来随机指定UA参数,然后写进DOWNLOADER_MIDDLEWARES 参数中,并指定一个整数值代表其在中间件中的顺序,一般使用scarpy自动给你设置的值就可以,如上面的520,你可以看到520的顺序在DOWNLOADER_MIDDLEWARES_BASE 参数中排在默认的UA中间件scrapy.downloadermiddlewares.useragent.UserAgentMiddleware 后,在scrapy.downloadermiddlewares.retry.RetryMiddleware 中间件之前,scrapy的用意在于在scrapy.downloadermiddlewares.retry.RetryMiddleware 之前用户得解决完毕每个请求的请求头等参数问题,后面的默认中间件都不会再去覆盖这些参数,由此得出,你自己的UserAgentMiddleware 的值设置最好在500-550之间,但经我实际测试,其实只要大于0就可以,但是为了保持scapy内部中间件的默认顺序,自己瞎赋值可能会造成不正常运行,最好还是在500-550之间。当然,此时也可以设置'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,让scrapy不要调用自己的UA中间件了,可以提高一点效率。
下面我们来看几个跟本话题有关的几个中间件:
-
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100, 这是最先执行的中间件,用于请求robots文件,只有在ROBOTSTXT_OBEY = True 的情况下才会使用,此时会用到ROBOTSTXT_USER_AGENT 或USER_AGENT 的值。 -
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400, 加上默认请求头,也就是DEFAULT_REQUEST_HEADERS 的值在这个中间件的 process_request() 中会添加到每个请求中,如果你在DEFAULT_REQUEST_HEADERS 设置了UA,那么默认UA就设置进去了。 -
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500, 如果DEFAULT_REQUEST_HEADERS 没有设置UA,那么在这个中间件的 process_request() 中会代入USER_AGENT 的值作为默认UA,如果DEFAULT_REQUEST_HEADERS 设置了UA,那么就什么事都不做。 -
'baidu.middlewares.bdUserAgentMiddleware': 520, 也就是你自己写的UA中间件,设置了动态UA: from fake_useragent import UserAgent
?
class bdUserAgentMiddleware(UserAgentMiddleware):
? ?# 重写process_request方法,中途截获request并对其进行useragent随机取值操作
? ?def process_request(self, request, spider):
? ? ? ?# 随机从列表中取出一个作为useragent的值
? ? ? ?ua=UserAgent(path='./fake_useragent.json')
? ? ? ?request.headers['User-Agent']=ua.random 但是不管你在项目中使用自己的UA中间件设置随机UA还是在spider类中直接添加headers设置随机UA,里面的UA设置将会覆盖以上所有中间件的UA设置,这会导致USER_AGENT 参数及DEFAULT_REQUEST_HEADERS 里的UA参数无效。
看了这么多,那么我来考一下大家:
Q:如果同时指定了USER_AGENT的值和DEFAULT_REQUEST_HEADERS参数里的UA的值,在不调用自己的UserAgentMiddleware中间件及spider类中直接添加headers设置随机UA的情况下,scrapy内部取谁的值呢?
A:希望大家能畅所欲言。答案可以自行去测试。
以上是根据scrapy官方文档和相关博文,再结合自己测试和理解给大家整理的,如有错误,欢迎指教交流。
|