文章目录

  • 第二十章 scrapy登录与middlewares
    • 1. scrapy携带cookie模拟登录
      • 1.1 创建项目
      • 1.2 修改代码
      • 1.3 查看spider的源码
      • 1.4 重写start_requests(self)方法
      • 1.5 配置settings文件
      • 1.6 headers换成cookies
    • 2. scrapy发送post请求模拟登录
      • 2.1 form data里的数据
      • 2.2 检查数据是否在源码中
      • 2.3 创建一个scrapy项目和spider项目
      • 2.4 修改start_url并获取需要的数据
      • 2.5 汇总需要提交的数据
      • 2.6 提交数据
    • 3. scrapy另一种登录方式
      • 3.1 创建项目
      • 3.2 设置项目
      • 3.3 scrapy.FormRequest.from_response方法
      • 3.4 运行结果
    • 4. middlewares文件的讲解
      • 4.1 设置随机请求头
        • 4.1.1 设置随机user-agent
        • 4.1.2 fake-useragent
        • 4.1.3 用fake-useragent设置随机请求头
      • 4.2 设置代理IP
        • 4.2.1 普通方法设置ip
        • 4.2.2 在scrapy里面设置

第二十章 scrapy登录与middlewares

以前我们登录网站有两种方式:
一个是:直接携带cookie来请求页面
另一个:发送post请求携带数据进行模拟登录
当然selenium也能模拟登录(找到对应的input标签)。

1. scrapy携带cookie模拟登录

下面我们通过登录人人网案例来学习scrapy携带cookies登录方法。

1.1 创建项目

我们创建一个新的scrapy项目叫login

D:\work\爬虫\Day22>scrapy startproject login
New Scrapy project 'login', using template directory 'd:\python38\lib\site-packages\scrapy\templates\pro
ject', created in:D:\work\爬虫\Day22\loginYou can start your first spider with:cd loginscrapy genspider example example.comD:\work\爬虫\Day22>

然后我们cd 到login

D:\work\爬虫\Day22>cd loginD:\work\爬虫\Day22\login>

我们先放一下。下面我们要操作的是携带cookie登录人人网。http://www.renren.com/
这是一个社交平台。下面我们创建spider项目:

D:\work\爬虫\Day22\login>scrapy genspider renren renren.com
Created spider 'renren' using template 'basic' in module:login.spiders.renrenD:\work\爬虫\Day22\login>

1.2 修改代码

现在我们可以打开查看我们刚刚创建的项目:

第一步我们先把start_url改了,改成详情页面的url

如果我们添加一个cookie值就能登录了,但是怎么添加呢?添加到什么地方呢?
response是已经拿到的响应结果,所以我们添加在parse这个方法的下面是没有意义的。

1.3 查看spider的源码

所以,我们一定要在请求地址的时候就携带cookie。下面我们分析一下spider的源码,Ctrl+点击spider

我们看到里面的代码:

"""
Base class for Scrapy spidersSee documentation in docs/topics/spiders.rst
"""
import logging
import warnings
from typing import Optionalfrom scrapy import signals
from scrapy.http import Request
from scrapy.utils.trackref import object_ref
from scrapy.utils.url import url_is_from_spider
from scrapy.utils.deprecate import method_is_overriddenclass Spider(object_ref):"""Base class for scrapy spiders. All spiders must inherit from thisclass."""name: Optional[str] = Nonecustom_settings: Optional[dict] = Nonedef __init__(self, name=None, **kwargs):if name is not None:self.name = nameelif not getattr(self, 'name', None):raise ValueError(f"{type(self).__name__} must have a name")self.__dict__.update(kwargs)if not hasattr(self, 'start_urls'):self.start_urls = []@propertydef logger(self):logger = logging.getLogger(self.name)return logging.LoggerAdapter(logger, {'spider': self})def log(self, message, level=logging.DEBUG, **kw):"""Log the given message at the given log levelThis helper wraps a log call to the logger within the spider, but youcan use it directly (e.g. Spider.logger.info('msg')) or use any otherPython logger too."""self.logger.log(level, message, **kw)@classmethoddef from_crawler(cls, crawler, *args, **kwargs):spider = cls(*args, **kwargs)spider._set_crawler(crawler)return spiderdef _set_crawler(self, crawler):self.crawler = crawlerself.settings = crawler.settingscrawler.signals.connect(self.close, signals.spider_closed)def start_requests(self):cls = self.__class__if not self.start_urls and hasattr(self, 'start_url'):raise AttributeError("Crawling could not start: 'start_urls' not found ""or empty (but found 'start_url' attribute instead, ""did you miss an 's'?)")if method_is_overridden(cls, Spider, 'make_requests_from_url'):warnings.warn("Spider.make_requests_from_url method is deprecated; it ""won't be called in future Scrapy releases. Please ""override Spider.start_requests method instead "f"(see {cls.__module__}.{cls.__name__}).",)for url in self.start_urls:yield self.make_requests_from_url(url)else:for url in self.start_urls:yield Request(url, dont_filter=True)def make_requests_from_url(self, url):""" This method is deprecated. """warnings.warn("Spider.make_requests_from_url method is deprecated: ""it will be removed and not be called by the default ""Spider.start_requests method in future Scrapy releases. ""Please override Spider.start_requests method instead.")return Request(url, dont_filter=True)def _parse(self, response, **kwargs):return self.parse(response, **kwargs)def parse(self, response, **kwargs):raise NotImplementedError(f'{self.__class__.__name__}.parse callback is not defined')@classmethoddef update_settings(cls, settings):settings.setdict(cls.custom_settings or {}, priority='spider')@classmethoddef handles_request(cls, request):return url_is_from_spider(request.url, cls)@staticmethoddef close(spider, reason):closed = getattr(spider, 'closed', None)if callable(closed):return closed(reason)def __str__(self):return f"<{type(self).__name__} {self.name!r} at 0x{id(self):0x}>"__repr__ = __str__# Top-level imports
from scrapy.spiders.crawl import CrawlSpider, Rule
from scrapy.spiders.feed import XMLFeedSpider, CSVFeedSpider
from scrapy.spiders.sitemap import SitemapSpider

1.4 重写start_requests(self)方法

我们看到里面有一个方法叫start_requests(self)

def start_requests(self):cls = self.__class__if not self.start_urls and hasattr(self, 'start_url'):raise AttributeError("Crawling could not start: 'start_urls' not found ""or empty (but found 'start_url' attribute instead, ""did you miss an 's'?)")if method_is_overridden(cls, Spider, 'make_requests_from_url'):warnings.warn("Spider.make_requests_from_url method is deprecated; it ""won't be called in future Scrapy releases. Please ""override Spider.start_requests method instead "f"(see {cls.__module__}.{cls.__name__}).",)for url in self.start_urls:yield self.make_requests_from_url(url)else:for url in self.start_urls:yield Request(url, dont_filter=True)

这个方法是开始发起请求的,可以携带数据。我们可以在spider项目文件里重写这个类,让它可以携带数据:

import scrapyclass RenrenSpider(scrapy.Spider):name = 'renren'allowed_domains = ['renren.com']start_urls = ['http://renren.com/329713622/profile']# 重写start_requests方法def start_requests(self):# 下面这个cookies是在我的登录页面找的cookies = 'anonymid=klb0kule-8lfij3; depovince=GW; _r01_=1; ick_login=4828c896-52cd-48c0-96bb-45b43251b195; taihe_bi_sdk_uid=e124793e2750f492bfece109d8153031; taihe_bi_sdk_session=d7ad6d364212a9817407126a43884e01; jebecookies=7d6f5514-4b66-42b8-afb7-3e11f1fe89ad|||||; _de=8372EB449AECC7A844B0A57815E527E7696BF75400CE19CC; p=75fded0e021a9840d2f47016588413232; ap=329713622; first_login_flag=1; ln_uact=lgh67891@163.com; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=70a73522c9b6ca1a2a8316b46cc99b302; societyguester=70a73522c9b6ca1a2a8316b46cc99b302; id=329713622; xnsid=4a363019; ver=7.0; loginfrom=null; wp_fold=0'# 下面定义一个headers存放携带数据headers = {'cookie':cookies}# 下面发起请求yield scrapy.Request(url=self.start_urls[0],callback=self.parse,headers=headers)def parse(self, response):print(response.text)pass

之前没有加入start_requests(self)方法的时候,运行后直接运行了parse(self, response)方法,现在运行的时候会先发现start_requests(self)方法,发起请求的时候会携带headers里面的数据,然后返回的结果交给parse(self, response)方法处理。
其中Request()方法里面的传参可以Ctrl+点Reques查看:

class Request(object_ref):def __init__(self, url, callback=None, method='GET', headers=None, body=None,cookies=None, meta=None, encoding='utf-8', priority=0,dont_filter=False, errback=None, flags=None, cb_kwargs=None):

里面有headers也有cookies,当然你也可以直接把cookies当作参数传入,但是这里用headers方便,可以携带更多的额请求数据。下面我们加入存储语句运行一下,看看结果:

    def parse(self, response):with open('renren.html','w',encoding='utf-8') as f:f.write(response.text)

1.5 配置settings文件

下面我们设置一下settings文件:

LOG_LEVEL = 'WARNING'
ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en',
}

再创建一个start文件:

from scrapy import cmdline
cmdline.execute('scrapy crawl renren'.split())

我们运行一下:

这是保存的结果,我们发现并不是一个登录后的页面。说明我们携带的cookies没有起作用。

1.6 headers换成cookies

那么我们改一种携带方式:

 yield scrapy.Request(url=self.start_urls[0],callback=self.parse,cookies=cookies

运行一下:
报了个错

AttributeError: 'str' object has no attribute 'get'

cookies应该是字典,下面我们把cookies做成字典的格式,注意看注释:

    def start_requests(self):# 下面这个cookies是在我的登录页面找的cookies = 'anonymid=klb0kule-8lfij3; depovince=GW; _r01_=1; ick_login=4828c896-52cd-48c0-96bb-45b43251b195; taihe_bi_sdk_uid=e124793e2750f492bfece109d8153031; taihe_bi_sdk_session=d7ad6d364212a9817407126a43884e01; jebecookies=7d6f5514-4b66-42b8-afb7-3e11f1fe89ad|||||; _de=8372EB449AECC7A844B0A57815E527E7696BF75400CE19CC; p=75fded0e021a9840d2f47016588413232; ap=329713622; first_login_flag=1; ln_uact=lgh67891@163.com; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=70a73522c9b6ca1a2a8316b46cc99b302; societyguester=70a73522c9b6ca1a2a8316b46cc99b302; id=329713622; xnsid=4a363019; ver=7.0; loginfrom=null; wp_fold=0'cookies = {i.split('=')[0]:i.split('=')[1] for i in cookies.split('; ')} # 注意分号后面有个空格# 下面定义一个headers存放携带数据# headers = {#     'cookie':cookies# }# 下面发起请求yield scrapy.Request(url=self.start_urls[0],callback=self.parse,cookies=cookies)

注意,我们在把cookies转化成字典的时候用了一个列表推导式,而且分割数据的时候,分号后面有个空格。如果忘记空格,数据还是不对的。这次我们再运行一下:

这次没有报错了,而且出现了我的名字。用浏览器打开renren.html看看

终于登录成功了。
这是我们通过cookies模拟登录的方法。

2. scrapy发送post请求模拟登录

下面我们通过模拟登录github来学习一下 scrapy发送post请求模拟登录。
登录地址:https://github.com/login

我们看到登录界面,需要携带的数据包括账号和密码。
我们输入账号和一个错误的密码点击sign in,在network里面出现一个session

我们看看headers它的Request URL: https://github.com/session

我们正是向这个地址来发送携带数据的。

2.1 form data里的数据

在下面的form data里是我们需要携带的数据:

commit: Sign in
authenticity_token: Gjc0o0rNitvg1NdeTMFRgHJzg9/vK/l6uogUEWvBuZIIeuaXhGdWuUPkOgY6EeCp0qBH7ed74i9VHgTXXn6QpA==
login: Daniel-Li****
password: ********
trusted_device:
webauthn-support: supported
webauthn-iuvpaa-support: supported
return_to:
allow_signup:
client_id:
integration:
required_field_415c:
timestamp: 1613704775684
timestamp_secret: dc766a4eb64494ddae95bb6ff8f3f9add68cd49fda55d33e06493c418893dc4c

可以自己验证一下,这些数据里面不是都需要的。不必要的数据可以删除。
注意,有些数据,在二次请求的时候是会改变的,比如authenticity_token

所以我们必须动态的拿到这些数据,然后作为要携带的数据添加,再发出请求。

2.2 检查数据是否在源码中

那我们检查一下这个数据在不在源代码里面,右键>检查>Ctrl+F

在这里是有的,我们再右键>查看网页源码>Ctrl+F

我们看到这里也有,说明这个在源码中。同理,我们可以检查其他的元素,也都在源码中。

2.3 创建一个scrapy项目和spider项目

下面我们创建一个scrapy项目叫glogin:

D:\work\爬虫\Day22>scrapy startproject glogin
New Scrapy project 'glogin', using template directory 'd:\python38\lib\site-packages\scrapy\templates\pr
oject', created in:D:\work\爬虫\Day22\gloginYou can start your first spider with:cd gloginscrapy genspider example example.comD:\work\爬虫\Day22>cd gloginD:\work\爬虫\Day22\glogin>

下面我们再创建一个spider项目,叫github


D:\work\爬虫\Day22>cd gloginD:\work\爬虫\Day22\glogin>scrapy genspider github github.com
Created spider 'github' using template 'basic' in module:glogin.spiders.githubD:\work\爬虫\Day22\glogin>

项目创建成功

2.4 修改start_url并获取需要的数据

第一步我们还是先修改一下start_url,改成要登录的页面的url


class GithubSpider(scrapy.Spider):name = 'github'allowed_domains = ['github.com']start_urls = ['https://github.com/login']def parse(self, response):pass

下面我们尝试在parse方法里面获取这个页面我们需要的数据,比如:authenticity_token

 def parse(self, response):authenticity_token = response.xpath('//input[@name="authenticity_token"]/@value').extract_first()  # 获得数据print(authenticity_token)pass

我们看看打印结果,不过要配置一下Settings并创建一个start文件,这里就不再介绍。

LOG_LEVEL = 'WARNING'
ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en',
}

运行后拿到的数据

D:\Python38\python.exe D:/work/爬虫/Day22/glogin/start.py
SnW/Pif/45or9ioSg5+Ar8gqfJBAyChpRsi4iwJFQrTngRlmIzXLhCmqMXACnTL0Ognn30n57FkNRxrsf82blA==Process finished with exit code 0

下面我们用同样的方法获取其他的需要携带的动态数据,固定不变的数据就直接填写,动态数据通过parse方法解析获取。

 def parse(self, response):commit = 'Sign in'authenticity_token = response.xpath('//input[@name="authenticity_token"]/@value').extract_first() # 获得数据login = 'Daniel - ********'password = 'lgh*******'timestamp = response.xpath('//input[@name="timestamp"]/@value').extract_first() # 时间戳timestamp_secret = response.xpath('//input[@name="imestamp_secret"]/@value').extract_first() # 时间戳密钥

2.5 汇总需要提交的数据

下面我们定义一个字典来提交数据:

# 定义一个字典来提交数据data = {'commit': commit,'authenticity_token': authenticity_token,'login': login,'password': password,'timestamp': timestamp,'timestamp_secret': timestamp_secret,}pass

2.6 提交数据

下面要做的是提交数据,发起请求。需要注意的是:

  • 我们提交数据发起请求的url不再是Start_url。而是:https://github.com/session
  • 用scrapy.Request()方法无法提交数据,需要换用另一种scrapy.FormRequest()方法。
yield scrapy.FormRequest(# 提交数据的urlurl='https://github.com/session',# 携带数据formdata=data,# 回调函数callback=self.after_login # 新定义一个方法)
def after_login(self,response):print(response)

我们再运行一下:

<200 https://github.com/session>

我们把数据保存为html文件:

    def after_login(self,response):# 保存文件with open('github.html','w',encoding='utf-8') as f:f.write(response.text)

运行结果:

用浏览器打开一下:

账号密码错误。修改一下再次运行:

这次登录成功!

总结:

  • 先在页面上寻找是否有需要的数据
  • 发送post请求方式用scrapy.FormRequest(formData=data)
  • 如果我们需要什么方法,我们可以点击spider看源码,从里面找到自己需要的方法。

3. scrapy另一种登录方式

除了上面案例里的登录方式,还有一种更简单的登录方式,我们来介绍一下。

3.1 创建项目

我们在glogin里面新建一个Spider项目叫github2


D:\work\爬虫\Day22\glogin>scrapy genspider github2 github.com
Created spider 'github2' using template 'basic' in module:glogin.spiders.github2D:\work\爬虫\Day22\glogin>

3.2 设置项目

我们第一步仍然改一下start_url


class Github2Spider(scrapy.Spider):name = 'github2'allowed_domains = ['github.com']start_urls = ['https://github.com/login']

下面我们要采用一个非常好的方法,这种方法不需要携带那么多的数据。我们在上一个github方法里面改一下yield scrapy.FormRequest()

yield scrapy.FormRequest.from_response

在之前的FormRequest后面加个英文的点,在提示里就有这个方法。我们按住Ctrl键点进去:

我们看到这是一个类方法。在参数里有一个response,也就是说这个方法直接传入了上一个方法(parse(self, response))的返回结果。

3.3 scrapy.FormRequest.from_response方法

那么这个代码可以这么写:

import scrapyclass Github2Spider(scrapy.Spider):name = 'github2'allowed_domains = ['github.com']start_urls = ['https://github.com/login']def parse(self, response):yield scrapy.FormRequest.from_response(response=response,formdata={},callback=self.after_login)passdef after_login(self, response):# 保存文件with open('github.html', 'w', encoding='utf-8') as f:f.write(response.text)

我们在 formdata={}里面补充我们的账号和密码数据就可以了。为什么可以这么简单呢?上一个方法里面我们携带了许多数据,而且是提前定义方法得到这些数据,然后携带登录的。为什么这个方法可以不用携带那些数据呢?这是因为这种请求方式是基于response数据发起的请求,从from_response的字面意思你就可以了解到。实际上在这个请求前已经获取了“https://github.com/login”这个页面返回的所有数据。当然,有一个数据是不会得到的,就是我们的账号密码,我们按照之前的格式补充一下就可以了。保存的文件名也改一下:

import scrapyclass Github2Spider(scrapy.Spider):name = 'github2'allowed_domains = ['github.com']start_urls = ['https://github.com/login']def parse(self, response):yield scrapy.FormRequest.from_response(response=response,formdata={ 'login':'lgh67891@163.com','password':'lgh******'},callback=self.after_login)passdef after_login(self, response):# 保存文件with open('github2.html', 'w', encoding='utf-8') as f:f.write(response.text)

改一下start文件

from scrapy import cmdline
cmdline.execute(['scrapy','crawl','github2'])

3.4 运行结果

运行一下:

用浏览器打开一下

已经登录成功了。

4. middlewares文件的讲解

在settings文件中有两个内容没有解锁过,我们今天介绍一下,就是下载中间件爬虫中间件

# 爬虫中间件
#SPIDER_MIDDLEWARES = {
#    'glogin.middlewares.GloginSpiderMiddleware': 543,
#}# 下载中间件
#DOWNLOADER_MIDDLEWARES = {
#    'glogin.middlewares.GloginDownloaderMiddleware': 543,
#}

先说一下middleware文件,我们再复习一下scrapy工作流程:

首先创建了scrapy项目,然后创建了爬虫项目,在爬虫项目里面有个start_urls,是个列表,可以有多个。Spider把url给引擎,引擎又把url给了Scheduler(调度器),做一些入列的操作,又取出一个给下载器,还是经过了引擎,引擎就需要把你要爬取数据的url给下载器,在给的过程中需要经过一个DownloaderMiddlewares(下载中间件),由DownloaderMiddlewares再给Downloader(下载器)。下载器就去爬取数据,爬取数据完了,我把response响应结果给Spider(爬虫),你去解析,去处理。但并不是直接给Spider,而是先给引擎,又经历了DownloaderMiddlewares,引擎把数据给Spider时经过了SpiderMiddlewares(爬虫中间件)。解析完了数据给pipelines存储,或者有next_url通过SpiderMiddlewares给引擎,引擎又给Scheduler(调度器),再做一次循环。
其中用的最多的是DownloaderMiddlewares,它在把url给下载器之前就做了一些操作,比如设置代理,更换请求头,来达到反反爬虫的目的。
我们打开Middlewares文件看一下:

代码有点多,我们可以折叠起来:

一共两个类:下载中间件爬虫中间件
我们主要看一下下载中间件的两个方法:

class GloginDownloaderMiddleware:# 中间的方法省略def process_request(self, request, spider):# Called for each request that goes through the downloader# middleware.# Must either:# - return None: continue processing this request# - or return a Response object# - or return a Request object# - or raise IgnoreRequest: process_exception() methods of#   installed downloader middleware will be calledreturn Nonedef process_response(self, request, response, spider):# Called with the response returned from the downloader.# Must either;# - return a Response object# - return a Request object# - or raise IgnoreRequestreturn response# 后面的方法省略

def process_request(self, request, spider):里面有两个参数,一个是request,发起请求,另一个是spider,爬虫对象。

def process_request方法的返回值默认是返回None。如中间件返回值为None就会爬爬虫给下一个中间件处理;假如有一个中间件返回的是一个response对象,那么执行的就将是 def process_response方法,就不会在把下一个request对象给下载器了。就由中间件直接给引擎。

4.1 设置随机请求头

我们在day22里新建一个项目:

D:\work\爬虫\Day22>scrapy startproject mw
New Scrapy project 'mw', using template directory 'd:\python38\lib\site-packages\scrapy\templates\project'
, created in:D:\work\爬虫\Day22\mwYou can start your first spider with:cd mwscrapy genspider example example.comD:\work\爬虫\Day22>

cd到mw里面,然后创建一个爬虫项目ua:

D:\work\爬虫\Day22\mw>scrapy genspider ua httpbin.org
Created spider 'ua' using template 'basic' in module:mw.spiders.uaD:\work\爬虫\Day22\mw>

爬虫文件也创建完了,httpbin.org是一个特殊网站,如果我们输入user-agent,回车后就会返回一个user-agent的值。方便检验。

第一步我们先把起始url改成user-agent的url。

    start_urls = ['http://httpbin.org/user-agent']

我们新建一个start文件:

from scrapy import cmdlinecmdline.execute(['scrapy','crawl','ua'])

设置一下settings

LOG_LEVEL = 'WARNING'
ROBOTSTXT_OBEY = False
# DEFAULT_REQUEST_HEADERS = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en',
}
# 最后一个先不打开

打印一下返回结果:

import scrapyclass UaSpider(scrapy.Spider):name = 'ua'allowed_domains = ['httpbin.org']start_urls = ['http://httpbin.org/user-agent']def parse(self, response):print(response.text) # 打印返回值pass

我们运行一下:

{"user-agent": "Scrapy/2.4.1 (+https://scrapy.org)"
}

返回的显然不是一个正确的结果。别人一看就知道是一个爬虫程序。下面我们把headrs解锁

DEFAULT_REQUEST_HEADERS = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36','Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language': 'en',
}

再运行一次:

{"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
}

我们看到返回值就是我们的user-agent了。

4.1.1 设置随机user-agent

我们的这个headers是写死了的,我们可以随机生成user-agent,用不同的user-agent来爬取。具体方式是可以在settings里定义一个user-agent列表,然后通过random函数来随机提取。但今天我们通过middlewares来解决这个问题。打开middlewares文件,我们看到有两个中间件。

我们可以自己定义一个中间件:

class UserAgentDownloaderMiddleware:USER_AGENTS = ["Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)","Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)","Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)","Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0","Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"]def process_request(self, request, spider):user_agent = random.choice(self.USER_AGENTS) #记得要先导入random模块request.headers['User-Agent'] = user_agent # 通过这一句发送过去

这里需要注意三点:

  • 先导入random模块
  • 复制一个列表进去,里面是存储好的urser-agent
  • 通过request.headers语句将生成的’User-Agent’发送给引擎。
    我们运行一下:
{"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
}

这仍然是我们之前写死的 “user-agent”,原因是我们没有打开settings里的DOWNLOADER_MIDDLEWARES

现在我们打开,并将我们自己写的middlewares复制进去

DOWNLOADER_MIDDLEWARES = {# 'mw.middlewares.MwDownloaderMiddleware': 543,'mw.middlewares.UserAgentDownloaderMiddleware': 543,}

为了方便看打印结果,我们设置一下在ur的parse方法里:

    def parse(self, response):print(response.text) # 打印返回值yield scrapy.Request(self.start_urls[0],dont_filter=True)pass

我们希望循环打印,所以把start_url通过 yield scrapy.Request方法发送给引擎。但是,如果我们没有设置后面的dont_filter=True去重参数为False,scrapy会自动去重。所以我们要把自动去重设置为假,这样才能一直的发送start_url。另外我们把Settings里的DOWNLOAD_DELAY = 3打开,这样可以每三秒打印一次,方便观察。我们运行一下:

D:\Python38\python.exe D:/work/爬虫/Day22/mw/start.py
{"user-agent": "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
}{"user-agent": "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)"
}{"user-agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1"
}{"user-agent": "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
}{"user-agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)"
}{"user-agent": "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
}Process finished with exit code -1

我们看到了不同的user-agent被随机打印出来了。

总结:

  • 我们在Middlewares这个文件中设置随机user-agent
  • 重新定义process_request方法
def process_request(self, request, spider):user_agent = random.choice(self.USER_AGENTS)request.headers['User-Agent'] = user_agent# 默认返回None
  • 在settings里面不要忘记开启Middlewares
    补充:
 def parse(self, response):print(response.text) # 打印返回值yield scrapy.Request(self.start_urls[0],dont_filter=True)

通过这个设置,让我们循环打印user-agent。

4.1.2 fake-useragent

fake-useragent里面有个Useragent()类,可以随机生成user-agent
常用的方法是:

# 1. ua.random  可以随机生成u-a
# 2. 生成指定的u-a 例如:谷歌的,ie的火狐的

如果我们想使用这个方法,我们需要先安装:

pip install fake-useragent

下面我们新建一个文件练习一下:

from fake_useragent import UserAgent
import time
ua = UserAgent()for i in range(10):s = ua.randomtime.sleep(1)print(s)

运行一下:

D:\Python38\python.exe D:/work/爬虫/Day22/fake-useragent_practise.py
Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1464.0 Safari/537.36
Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36
Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17
Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1467.0 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20130331 Firefox/21.0
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; ar) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4
Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/24.0.1295.0 Safari/537.15
Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36Process finished with exit code 0

我们看到随机打印了10个不同的user-agent
我们也可以指定一个ua

rom fake_useragent import UserAgent
import time
ua = UserAgent()s = ua.firefox
print(s)

结果:

Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:27.0) Gecko/20121011 Firefox/27.0

我们也可以循环打印多个:

rom fake_useragent import UserAgent
import time
ua = UserAgent()
for i in range(3):time.sleep(1.5)s = ua.firefoxprint(s)

结果

D:\Python38\python.exe D:/work/爬虫/Day22/fake-useragent_practise.py
Mozilla/5.0 (Windows NT 6.1; rv:14.0) Gecko/20100101 Firefox/18.0.1
Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0
Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0Process finished with exit code 0

4.1.3 用fake-useragent设置随机请求头

第一步:先导入
在middlewares文件里先导入fake-useragent模块
第二步:重写process_request方法

# 方式二def process_request(self, request, spider):ua = UserAgent() # 实例化类user_agent_str = ua.randomrequest.headers['User-Agent'] = user_agent_str

我们start运行一下:

D:\Python38\python.exe D:/work/爬虫/Day22/mw/start.py
{"user-agent": "Mozilla/5.0 (X11; NetBSD) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36"
}{"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0"
}{"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1623.0 Safari/537.36"
}{"user-agent": "Mozilla/5.0 (Windows NT 6.1; U; nl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 Opera 11.01"
}{"user-agent": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36"
}Process finished with exit code -1

这里随机打印了五个 “user-agent”,我们观察一下是不同的。

4.2 设置代理IP

有时候反爬虫会对访问频繁的ip进行限制,这时候就用到了代理ip的知识。那么首先怎么获取我们自己的ip呢,介绍两种方式,第一种就是我们上面说过的一个网站http://httpbin.org/我们可以直接输入http://httpbin.org/ip结果就返回了本地的ip:

另一种方式,我们可以登录一个网站叫ipip.net也可以看到你的ip

4.2.1 普通方法设置ip

我们想通过requests方法设置ip。
新建一个文件set_ip_01, ‘http://httpbin.org/ip’ 我们就用这个网站做测试。

import requestsurl = 'http://httpbin.org/ip'  # 我们就用这个网站做测试
res =requests.get(url)
print(res.text)

运行一下:

{"origin": "111.19.43.***"
}

就是我们刚才在网站上显示的结果。注意,这个ip是和我们电脑上显示的ipv4是不同的,我们可以在命令行窗口输入:ipconfig回车

这个是我本机的ip地址,也就是说我内网的私有地址。这个ip地址只能适用于局域网,不能用于外网。
我们通过网页查询到的ip是我们主机的一个ip,就是网络宽带运营商给我们分配的ip地址,你使用不同的网络,这个ip地址会不同。
那么如果我们要设置一个ip我们需要找一个ip,我们可以百度输入“快代理”

进入后,选免费代理。我们可以随便选择一个:36.250.156.241

代码这样写:

import requestsurl = 'http://httpbin.org/ip'  # 我们就用这个网站做测试
# 设置代理ip地址
proxy = {'http':'123.169.124.145:9999'   # 9999是端口
}
res =requests.get(url,proxies= proxy)
print(res.text)

结果报错了,说明这个ip不能用:

我们换一个国内普通代理:36.112.139.146端口是3128
结果也不行。那我们就不尝试了。设置代理的作用是:

  • 隐藏自己真实的ip
  • 突破自身ip访问限制

代理ip的透明度

  • 透明 服务器知道你使用了代理ip,也知道你真实的ip
  • 匿名 服务器知道你使用了代理ip,但不知道你真实的ip
  • 高匿 服务器不知道你使用了代理ip,也不知道你真实的ip

来源:网上购买

如豌豆http,快代理等。

4.2.2 在scrapy里面设置

下面我们在scrapy里面设置,打开middlewares文件,新定义一个类class “IPProxyDownloaderMiddleware:”:

class IPProxyDownloaderMiddleware:PROXIES = {{"ip":"114.97.199.97","port":3617,"expire_time":"2021-02-22 02:35:50"},{"ip":"123.134.177.149","port":23564,"expire_time":"2021-02-22 02:27:46"}}def process_request(self, request, spider):proxy = random.choice(self.PROXIES)# ip_url的格式:http://127.0.0.1:8889proxy_url = 'http://' + proxy['ip'] + ':' + str(proxy['port']) # 由于端口返回的是整数格式,需要转化成字符串request.meta['proxy'] = proxy_url # 这里用的是meta


注意看注释。
然后我们打开Settings把我们写的新的middlewares复制粘贴一下:

DOWNLOADER_MIDDLEWARES = {# 'mw.middlewares.MwDownloaderMiddleware': 543,#  'mw.middlewares.UserAgentDownloaderMiddleware': 543,'mw.middlewares.IPProxyDownloaderMiddleware':200,# 后面的数字是随便写的}

然后把ua里面的start_url改一下:

    start_urls = ['http://httpbin.org/ip']

其他的不变。运行一下:

我这个因为ip不行,你可以购买付费的。这里可以自己换ip尝试。代码就是这个写法。

总结:

  • 首先在代理网站购买真实有效的代理ip
  • 通过这个网站返回一个json数据 (ip port datatime)
  • middlewares里面创建一个中间件
  • 在settings里面设置一下我们创建的中间件

爬虫(22)scrapy登录与middlewares相关推荐

  1. 爬虫教程( 2 ) --- 爬虫框架 Scrapy、Scrapy 实战

    From:https://piaosanlang.gitbooks.io/spiders/content/ scrapy-cookbook :https://scrapy-cookbook.readt ...

  2. Python学习笔记——爬虫之Scrapy框架

    目录 Scrapy 框架 Scrapy的安装介绍 Windows 安装方式 Ubuntu 需要9.10或以上版本安装方式 入门案例 启动Scrapy Shell Item Pipeline Spide ...

  3. 爬虫(20)Scrapy知识补充+腾讯招聘案例+古诗文详情页+总结

    文章目录 第十八章 腾讯招聘案例 1. 腾讯招聘案例 2. 代码实现 2.1 配置项目 2.2 解析数据 2.3 翻页处理 2.4 获取详情页信息 3. 古诗词网补充 3.1 验证是否在源码中 3.2 ...

  4. Python爬虫总结——Scrapy+Gerapy部署网络爬虫

    Python爬虫总结--从基础爬虫到Scrapy+Gerapy部署网络爬虫 前言 一.常用pip模块介绍 1.NumPy库 2.Pandas库 3.Requests库 4.BeautifulSoup库 ...

  5. pythonscrapy爬虫_Python 爬虫:Scrapy 实例(二)

    原标题:Python 爬虫:Scrapy 实例(二) 稍微增加点难度,做个所需项目多一点的,并将的结果以多种形式保存起来.我们就从网络天气预报开始. 首先要做的是确定网络天气数据的来源.打开百度,搜索 ...

  6. python 爬虫实例-Python 爬虫:Scrapy 实例(二)

    原标题:Python 爬虫:Scrapy 实例(二) 稍微增加点难度,做个所需项目多一点的,并将的结果以多种形式保存起来.我们就从网络天气预报开始. 首先要做的是确定网络天气数据的来源.打开百度,搜索 ...

  7. 精通python爬虫框架-精通Python爬虫框架Scrapy PDF 中文清晰版

    给大家带来的一篇关于Python爬虫相关的电子书资源,介绍了关于Python.爬虫.框架.Scrapy方面的内容,本书是由人民邮电出版社出版,格式为PDF,资源大小8.6 MB,迪米特里奥斯编写,目前 ...

  8. python爬虫之Scrapy框架,基本介绍使用以及用框架下载图片案例

    一.Scrapy框架简介 Scrapy是:由Python语言开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据,只需要实现少量的代码,就能够快速的抓取. S ...

  9. python数据分析案例2-1:Python练习-Python爬虫框架Scrapy入门与实践

    本文建立在学习完大壮老师视频Python最火爬虫框架Scrapy入门与实践,自己一步一步操作后做一个记录(建议跟我一样的新手都一步一步进行操作). 主要介绍: 1.scrapy框架简介.数据在框架内如 ...

最新文章

  1. 发送快递:配置静态路由
  2. qstring删除最后一个字符_Excel去掉最后一个字符两个方法,正反思维,你支持哪一个?...
  3. 比较Visual Studio中的两个文件
  4. jquery学习——选择器
  5. GDCM:获取dicom文件Sequence的长度的测试程序
  6. etcher制作mac启动盘_如何快速制作 macOS Mojave U盘启动盘,并重装Mac系统
  7. React 实现 百度搜索框(简易)
  8. Hadoop下载和源码阅读
  9. 有关PHP、HTML单引号、双引号转义以及转成HTML实体的那些事!
  10. 基于主动学习和克里金插值的空气质量推测
  11. 实战解析丨如何对Mysql连接请求的tcpdump内容进行分析
  12. 【翻译】Test-After Development is not Test-Driven Development
  13. Photoshop笔刷|如何正确导入笔刷?
  14. pfSense修改mbuf值
  15. Android Volley 源码解析(三),图片加载的实现
  16. 欧阳青C语言,[转载]恨君爱 作者 欧阳青
  17. mysql 事务一直running_事务一直running?记录一次事务异常导致的下单阻塞
  18. 机器学习 深度学习技术区别_体育技术机器学习金钱和灵感的圣杯
  19. 国产操作系统银河麒麟V10桌面系统文件共享配置
  20. linux钉钉-使用playonlinux 可以使用视频会议

热门文章

  1. 计算机毕业设计php的软件推销销售网站
  2. html加拼音注释,小学必背古诗80首+带拼音(注释彩打版)(31页)-原创力文档
  3. 计算机毕业设计django基于Python在线酒店管理系统
  4. 6月3号抖音显示服务器维护中,抖音搜索功能升级维护 期间无法进行用户搜索
  5. 学术搜索地图中机构自动展示-----------吴岳
  6. 十二、机器学习线性回归算法
  7. 签名服务器维护中,Unidbg + Web = Unidbg-server 手把手教你搭个签名服务器
  8. 苹果首台“双卡手机”,为什么只特供给部分地区?
  9. 设计冲刺工坊第四期——百格活动
  10. node-ffi使用指南(转载)