Python 分布式爬虫框架 Scrapy 7-4 通过download middleware随机切换User-agent

百度百科对User Agent的摘要:

User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

我们访问一个网站获取它的返回内容,可以通过Chrome、Firefox和IE等,或者我们写一段代码获取。

实际上我们的浏览器只是一个代理,服务器有时候需要知道是什么浏览器访问的,就需要写一段字符串来表明。也就是说User Agent是起标识作用的。

User Agent是放在请求头中的。这是浏览器自动加的,同一个浏览器,内容其实是一样的。

在进行修改之前,进行调试,在response中的request变量中的headers中,有一个User-Agent变量,它的值为:

想要实现随机切换User Agent十分简单,可以在settings.py中增一个user_agent_list变量:

user_agent_list = [
    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
    'Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/68.0',
]

然后在cnblogs.py中引入它:

from Spider.settings import user_agent_list

为了实现随机选择User Agent,引入:

import random

新建类变量:

    headers = {
        'HOST': "news.cnblogs.com",
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/68.0',
        'referer': 'https://news.cnblogs.com/'
    }

通过下面三句,就可以获得一个有随机User Agent的headers了:

random_index = random.randint(0, len(user_agent_list)-1)
random_agent = user_agent_list[random_index]
self.headers["User-Agent"] = random_agent

并在yield出去的Request对象中添加:

headers=headers

上面生成随机agent的的逻辑应该放在一个Request被yield出去之前,而headers变量应该放在类中。

接下来,request中的headers下的user agent会在下面二者中随机出现:

这样做有一个问题,需要我们在每一处Request被yield出去之前都加上那三条逻辑。

删除或注释除了settings中配置user_agent_list以外的的代码。

于是我们使用download middleware完成这项任务,先复习架构:

我们首先将settings.py中关于DOWNLOADER_MIDDLEWARES的注释取消:

DOWNLOADER_MIDDLEWARES = {
   'Spider.middlewares.SpiderDownloaderMiddleware': 543,
}

我们看看默认提供的一个UserAgentMiddleware:

刚刚默认的user-agent就是在这里设置的。

读代码,可以知道,如果settings.py中设置了USER_AGENT,就不会使用默认的Scrapy,所以可以在settings.py中加入:

# 默认的User Agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/68.0'

看这个也行,其实生成项目时,自动生成的middleware.py中的示例代码也交代了如何写middleware,比较重要的方法是process_request,所有对Request的处理都在这儿。

官网上说,downloader middleware是在request与response处理中的钩子框架,就是说它可以hook住一些函数,只要实现了这个函数的类,都可以被执行。用以全局修改Request和Response。

官网上还说,如果我们自己实现了UserAgentMiddleware,就必须把默认提供的设置为None,或者你可以把自己配置的middleware的数字设的大一点,这样就可以最后处理。下面把它置为None:

DOWNLOADER_MIDDLEWARES = {
    'Spider.middlewares.SpiderDownloaderMiddleware': 543,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None
}

在middlewares.py中实现自己的middleware:

import random
from Spider.settings import user_agent_list
class RandomUserAgentMiddlware(object):
    """
    随机更换user-agent
    """
    def __init__(self, crawler):
        super(RandomUserAgentMiddlware, self).__init__()
        self.user_agent_list = crawler.settings.get("user_agent_list", [])

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        def rdm():
            # 获取一个随机的user agent
            random_index = random.randint(0, len(user_agent_list) - 1)
            random_agent = user_agent_list[random_index]
            return random_agent

        request.headers.setdefault('User-Agent', rdm())

(函数中定义函数,是动态语言闭包的一种特性)

配置它:

DOWNLOADER_MIDDLEWARES = {
    'Spider.middlewares.SpiderDownloaderMiddleware': 543,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'Spider.middlewares.RandomUserAgentMiddlware': 600,
}

调试,果然可以。

但我们不这样做,因为这样做的话,user_agent_list是写死了的。把user_agent_list也注释掉。

github上搜索:

fake-useragent

直达:https://github.com/hellysmile/fake-useragent

我们先安装:

pip install fake-useragent

用法也很简单,我们可以在命令行中测试。

>>> from fake_useragent import UserAgent
>>> ua = UserAgent()
>>> ua.ie
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC
 6.0; Zune 4.0; Tablet PC 2.0; InfoPath.3; .NET4.0C; .NET4.0E)'
>>> ua.ie
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) chromeframe/10.0.648.205'
>>> ua.chrome
'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36'
>>> ua.chrome
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
>>> ua.random
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17'
>>> ua.random
'Mozilla/5.0 (Windows NT 6.1; rv:27.3) Gecko/20130101 Firefox/27.3'

这个包实际上是维护了一个url。这个url会更新,使得老版本的url不能使用,所以需要我们维护。

更改之前的middleware:

from fake_useragent import UserAgent
class RandomUserAgentMiddlware(object):
    """
    随机更换user-agent
    """
    def __init__(self, crawler):
        super(RandomUserAgentMiddlware, self).__init__()
        self.ua = UserAgent()

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        request.headers.setdefault('User-Agent', self.ua.random)

为了让这个middleware能根据我们的配置进行随机选择,我们在settings中加入一个配置:

# 随机user agent 类型
RANDOM_UA_TYPE = 'random'

并进一步更改middleware:

class RandomUserAgentMiddlware(object):
    """
    随机更换user-agent
    """
    def __init__(self, crawler):
        super(RandomUserAgentMiddlware, self).__init__()
        self.ua = UserAgent()
        self.ua_type = crawler.settings.get("RANDOM_UA_TYPE", "random")

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        def get_ua():
            return getattr(self.ua, self.ua_type)

        request.headers.setdefault('User-Agent', get_ua())

有其他配置,就按照这种模式来。

发布了101 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/liujh_990807/article/details/100110764
今日推荐