scrapy爬虫框架

scrapy爬虫框架

  • 一、scrapy的概念作用和工作流程
    • 1、scrapy的概念
    • 2、scrapy框架的作用
    • 3、scrapy的工作流程(重点)
      • 3.1 回顾之前的爬虫流程
      • 3.2 改写上述流程
      • 3.3 scrapy的流程
      • 3.4 scrapy的三个内置对象
      • 3.5 scrapy中每个模块的具体作用
  • 二、scrapy的入门使用
    • 1、安装scrapy
    • 2、scrapy项目开发流程
    • 3、创建项目
    • 4、创建爬虫
    • 5、完善爬虫
      • 5.1 在/spiders/itcast.py中修改内容
      • 5.2 定位元素以及提取数据、属性值的方法
      • 5.3 response响应对象的常用属性
    • 6、保存数据
      • 6.1 在pipelines.py文件中定义对数据的操作
      • 6.2 在settings.py配置启用管道
    • 7、运行scrapy
  • 三、scrapy数据建模与请求
    • 1、数据建模
      • 1.1 为什么要建模
      • 1.2 如何建模
      • 1.3 如何使用模板类
    • 2、翻页请求的思路
    • 3、构造Request对象,并发送请求
      • 3.1 实现方法
      • 3.2 网易招聘爬虫案例
      • 3.3 代码实现
      • 3.4 scrapy.Request的更多参数
    • 4、meta参数的使用
  • 四、scrapy模拟登录
    • 1、模拟登录的方法
      • 1.1 requests的模拟登录
      • 1.2 selenium的模拟登录
      • 1.3 scrapy的模拟登录
    • 2、scrapy携带cookies直接获取需要登录后的页面
      • 2.1 实现:重构scrapy的start_requests方法
      • 2.2 携带cookies登录GitHub
    • 3、scrapy.Request发送post请求
      • 3.1 发送post请求
        • 3.1.1 思路分析
        • 3.1.1 代码实现
  • 五、scrapy管道的使用
    • 1、pipeline 中常用的方法
    • 2、管道文件的修改
    • 3、开启管道
    • 4、pipeline使用注意点
  • 六、scrapy中间件的使用
    • 1、scrapy中间件的分类和作用
      • 1.1 scrapy中间件的分类
      • 1.2 scrapy中间件的作用
    • 2、下载中间件的使用方法
    • 3、定义实现随机User-Agent的下载中间件
      • 3.1 在settings.py中添加UA列表
      • 3.2 在middleware.py中完善代码
      • 3.3 在settings中设置开启自定义的下载中间件,设置方法同管道
    • 4、代理IP的使用
      • 4.1 思路分析
      • 4.2 具体实现
      • 4.3 检测代理IP是否可用
    • 5、在中间件中使用selenium
  • 七、scrapy_redis的概念、作用及流程
    • 1、分布式是什么
    • 2、scrapy_redis的概念
    • 3、scrapy_redis的作用
    • 4、scrapy_redis的工作流程
      • 4.1 回顾scrapy流程
      • 4.2 scrapy_redis的流程

一、scrapy的概念作用和工作流程

1、scrapy的概念

scrapy是一个python编写的开源网络爬虫框架。它是一个被设计用于爬虫网络数据、提取结构性数据的框架。

scrapy使用了twisted异步网络框架,可以加快我们的下载速度。
scrapy文档地址:https://scrapy-chs.readthedocs.io/zh-cn/0.24/intro/overview.html

2、scrapy框架的作用

少量的代码,就能够快速的抓取

3、scrapy的工作流程(重点)

3.1 回顾之前的爬虫流程

3.2 改写上述流程

3.3 scrapy的流程

在这里插入图片描述
其流程可以描述为:

  1. 爬虫中的起始url构造成request对象→爬虫中间件→引擎→调度器
  2. 调度器把request→引擎→下载中间件→下载器
  3. 下载器发送请求,获取response响应→下载中间件→引擎→爬虫中间件→爬虫
  4. 爬虫提取url地址,组装成request对象→爬虫中间件→引擎→调度器,重复步骤2
  5. 爬虫提取数据→引擎→管道处理和保存数据

注意:

  • 图中中文是为了方便理解后加上去
  • 图中绿色线条表示数据的传递
  • 注意图中中间件的位置,决定了其作用
  • 注意其中引擎的位置,所有模块之间相互独立,只和引擎进行交互

3.4 scrapy的三个内置对象

  • request请求对象:由url、method、post_data、headers等构成
  • response响应对象:由url、body、status、headers等构成
  • item数据对象:本质是个字典

3.5 scrapy中每个模块的具体作用

模块作用其他
Scrapy Engine(引擎)总指挥:负责数据和信号在不同模块之间的传递scrapy已经实现
Scheduler(调度器)一个队列,存放引擎发过来的request请求scrapy已经实现
Downloader(下载器)下载引擎发过来的request请求,并返回给引擎scrapy已经实现
Spider(爬虫)处理引擎发来的response,提取数据,提取url,并交给引擎需要手写
Item Pipeline(管道)处理引擎传过来的数据,比如存储需要手写
Downloader Middlewares(下载中间件)可以自定义的下载扩展,比如设置代理一般不用手写
Spider Middlewares(爬虫中间件)可以自定义request请求和进行response过滤一般不用手写

注意:

  • 爬虫中间件和下载中间件只是运行逻辑的位置不同,作用是重复的:如替换UA等。

二、scrapy的入门使用

1、安装scrapy

命令:sudo apt-get install scrapy 或者 pip/pip3 install scrapy

2、scrapy项目开发流程

  1. 创建项目:scrapy startproject mySpider
  2. 生成爬虫:scrapy genspider itcast itcast.cn
  3. 提取数据:根据网站结构在spider中实现数据采集相关内容
  4. 保存数据:使用pipeline进行数据后续处理和保存

3、创建项目

创建scrapy项目的命令:scrapy startproject <项目名称>
示例:scrapy startproject myspider
生成的目录和文件结果如下:
在这里插入图片描述

4、创建爬虫

在项目路径下执行如下命令:scrapy genspider <爬虫名字> <允许爬取的域名>
爬虫名字:作为爬虫运行时的参数
允许爬取的域名:设置爬虫的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不同则会被过滤掉。
示例:
cd myspider
scrapy genspider itcast itcast.cn
生成的目录和文件结果如下:
在这里插入图片描述

5、完善爬虫

在上一步生成出来的爬虫文件中编写指定网站的数据采集操作,实现数据提取

5.1 在/spiders/itcast.py中修改内容

import scrapyclass ItcastSpider(scrapy.Spider):  # 继承scrapy.Spidername = 'itcast'                     # 爬虫名字allowed_domains = ['itcast.cn']     # 允许爬取的范围start_urls = ['https://www.itheima.com/teacher.html#ajavaee']  # 开始爬取的url地址# 数据提取的方法,接收下载中间件传过来的responsedef parse(self, response):# 获取所有老师节点node_list = response.xpath('//div[@class="li_txt"]')# 遍历老师节点列表for node in node_list:temp = {}# xpath方法返回的是选择器对象列表,extract()用于从选择器对象中提取数据temp['name'] = node.xpath('./h3/text()')[0].extract()temp['title'] = node.xpath('./h4/text()')[0].extract()temp['desc'] = node.xpath('./p/text()')[0].extract()yield temp

注意:

  • scrapy.Spider爬虫类中必须有名为parse的解析
  • 如果网站结构层次比较复杂,也可以自定义其他解析函数
  • 在解析函数中提取的url地址如果要发送请求,则必须属于allowed_domains范围内,但是start_urls中的url地址不受这个限制
  • 启动爬虫时要注意启动的位置,在项目路径下启动
  • parse()函数中使用yield返回数据,注意解析函数中的yield能够传递的对象只能是:BaseItem,Request,dict,None

5.2 定位元素以及提取数据、属性值的方法

解析并获取scrapy爬虫中的数据:利用xpath规则字符串进行定位和提取

  1. response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
  2. 额外方法extract():返回一个包含有字符串的列表
  3. 额外方法extract_first():返回列表中的第一个字符串,列表为空则返回None

5.3 response响应对象的常用属性

  • response.url:当前响应的url地址
  • response.request.url:当前响应对应的请求的url地址
  • response.headers:响应头
  • response.request.headers:当前响应的请求头
  • response.body:响应体,也就是html代码,byte类型
  • response.status:响应状态码

6、保存数据

利用管道pipeline来处理(保存)数据

6.1 在pipelines.py文件中定义对数据的操作

  1. 定义一个管道类
  2. 重写管道类的process_item方法
  3. process_item方法处理完item之后必须返回给引擎
import jsonclass MyspiderPipeline:def __init__(self):self.file = open('itcast.json', 'w')def process_item(self, item, spider):# 将字典数据序列化json_data = json.dumps(item, ensure_ascii=False) + ',\n'# 将数据写入文件self.file.write(json_data)# 默认使用完管道之后需要将数据返回给引擎return itemdef __del__(self):self.file.close()

6.2 在settings.py配置启用管道

ITEM_PIPELINES = {'myspider.pipelines.MyspiderPipeline': 300,
}

配置项中键为使用的管道类,管道类使用.进行分割,第一个为项目目录,第二个为文件,第三个为定义的管道类。
配置项中值为管道的使用顺序,设置的数值越小越优先执行,该值一般设置为1000以内。

7、运行scrapy

命令:在项目目录下执行scrapy crawl <爬虫名字>
示例:scrapy crawl itcast

三、scrapy数据建模与请求

1、数据建模

通常在做项目的过程中,在items.py中进行数据建模

1.1 为什么要建模

  1. 定义item,即提前规划好哪些字段需要抓,防止手误;定义好之后,在运行过程中,系统会自动检查
  2. 配合注释一起可以清晰的知道要抓取哪些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典代替
  3. 使用scrapy的一些特定组件需要Item做支持,如scrapy的ImagesPipeline管道类。

1.2 如何建模

在items.py文件中定义要提取的字段:

class MyspiderItem(scrapy.Item):# define the fields for your item here like:name = scrapy.Field()   # 讲师的名字title = scrapy.Field()  # 讲师的职称desc = scrapy.Field()   # 讲师的介绍

1.3 如何使用模板类

模板类定义以后需要在爬虫中导入并且实例化,之后的使用方法和使用字典相同
itcast.py:

import scrapy
from myspider.items import MyspiderItemclass ItcastSpider(scrapy.Spider):  # 继承scrapy.Spidername = 'itcast'                     # 爬虫名字allowed_domains = ['itcast.cn']     # 允许爬取的范围start_urls = ['https://www.itheima.com/teacher.html#ajavaee']  # 开始爬取的url地址# 数据提取的方法,接收下载中间件传过来的responsedef parse(self, response):# 获取所有老师节点node_list = response.xpath('//div[@class="li_txt"]')# 遍历老师节点列表for node in node_list:item = MyspiderItem()  # 实例化后直接使用# xpath方法返回的是选择器对象列表,extract()用于从选择器对象中提取数据item['name'] = node.xpath('./h3/text()')[0].extract()item['title'] = node.xpath('./h4/text()')[0].extract()item['desc'] = node.xpath('./p/text()')[0].extract()yield item

注意:

  • from myspider.items import MyspiderItem这一行代码中注意item的正确导入路径,忽略pycharm标记的错误
  • python中的导入路径要诀:从哪里开始运行,就从哪里开始导入

2、翻页请求的思路

对于要提取如下图中所有页面上的数据该怎么办?

在这里插入图片描述
requests模块是如何实现翻页请求的:

  1. 找到下一页的url地址
  2. 调用requests.get(url)

scrapy实现翻页的思路:

  1. 找到下一页的url地址
  2. 构造url地址的请求对象,传递给引擎

3、构造Request对象,并发送请求

3.1 实现方法

  1. 确定url地址
  2. 构造请求,scrapy.Request(url, callback)
    • callback:指定解析函数名称,表示该请求返回的响应使用哪一个函数进行解析
  3. 把请求交给引擎:yield scrapy.Request(url, callback)

3.2 网易招聘爬虫案例

  • 通过爬取网易社会招聘的页面的招聘信息,学习如何实现翻页请求
  • 地址:https://hr.163.com/job-list.html
    在这里插入图片描述

思路分析:

  1. 获取首页的数据
  2. 寻找下一页的地址,进行翻页,获取数据

注意:

  1. 可以在settings中设置ROBOTS协议

    # False表示忽略网站的robots.txt协议,默认为True
    ROBOTSTXT_OBEY = False
    
  2. 可以在settings中设置User-Agent:

    # scrapy发送的每一个请求的默认UA都是设置的这个User-Agent
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
    

3.3 代码实现

  1. 网易社会招聘网站是一个JSON数据渲染的动态网页,网页源码中并不包含数据,所以不能使用xpath进行解析;对网站进行分析,找到请求页面动态加载JSON数据的请求,如下图所示:
    在这里插入图片描述
    在这里插入图片描述
    图中包含了每个职位的相关信息,此时的start_url地址发生了变化,需要进行更改,请求的方式为POST请求,相关的参数如下:
    在这里插入图片描述

  2. 该网站存在翻页,需要进行模拟翻页请求

  3. 将爬取到的数据存储到JSON文件中

  4. 代码如下:
    items.py:

    # Define here the models for your scraped items
    import scrapyclass WangyiItem(scrapy.Item):name = scrapy.Field()               # 职位名称workType = scrapy.Field()           # 工作性质workPlaceNameList = scrapy.Field()  # 工作地点productName = scrapy.Field()        # 所属产品firstPostTypeName = scrapy.Field()  # 职位类别recruitNum = scrapy.Field()         # 招聘人数reqEducationName = scrapy.Field()   # 学历reqWorkYearsName = scrapy.Field()   # 工作经验description = scrapy.Field()        # 职位描述requirement = scrapy.Field()        # 职位要求updateTime = scrapy.Field()         # 更新时间

    job.py:

    import jsonimport scrapyfrom wangyi.items import WangyiItem
    from datetime import datetimenext_page = 1  # 用来控制翻页的变量class JobSpider(scrapy.Spider):name = 'job'allowed_domains = ['hr.163.com']# start_urls = ['https://hr.163.com/job-list.html']start_urls = ['https://hr.163.com/api/hr163/position/queryPage']def start_requests(self):url = self.start_urls[0]# 起始url参数payload = {"currentPage": "1","pageSize": "10"}# 构建post请求yield scrapy.Request(url=url,body=json.dumps(payload),method='POST',callback=self.parse,headers={'Content-Type': 'application/json;charset=utf-8'})def parse(self, response):dic = response.json()job_list = dic['data']['list']item = WangyiItem()for job in job_list:item['name'] = job['name'].replace(u'\xa0', u' ')item['workType'] = job['workType']item['workPlaceNameList'] = str(job['workPlaceNameList']).replace('[', '').replace(']', '').replace("'", '')item['productName'] = job['productName']item['firstPostTypeName'] = job['firstPostTypeName']item['recruitNum'] = job['recruitNum']item['reqEducationName'] = job['reqEducationName']item['reqWorkYearsName'] = job['reqWorkYearsName']item['description'] = job['description'].replace('\t', '').replace('\n', '').replace('\\', '/')\.replace(u'\xa0', u' ')item['requirement'] = job['requirement'].replace('\t', '').replace('\n', '').replace(u'\xa0', u' ')item['updateTime'] = datetime.utcfromtimestamp(job['updateTime'] / 1000).strftime('%Y-%m-%d')yield item# 模拟翻页page_stutas = dic['data']['lastPage']  # 根据返回的数据来判断是否是最后一页,true为最后一页global next_pagenext_page = next_page + 1if not page_stutas:print("正在爬取第{}页···········".format(next_page))payload = {"currentPage": "{}".format(next_page),"pageSize": "10"}url = self.start_urls[0]yield scrapy.Request(url=url,body=json.dumps(payload),method='POST',callback=self.parse,headers={'Content-Type': 'application/json;charset=utf-8'})

    pipelines.py:

    # Define your item pipelines here
    import jsonclass WangyiPipeline:def __init__(self):self.file = open('wangyi.json', 'w', encoding='utf-8')def process_item(self, item, spider):# 将item对象强转为字典,该操作只能在scrapy中使用item = dict(item)# 将字典数据序列化json_data = json.dumps(item, ensure_ascii=False) + ',\n'# 将数据写入文件self.file.write(json_data)# 默认使用完管道之后需要将数据返回给引擎return itemdef __del__(self):self.file.close()
  5. 最终结果:
    在这里插入图片描述

3.4 scrapy.Request的更多参数

scrapy.Request(url[, callback, method="GET", headers, body, cookies, meta, dont_filter=False])

参数解释:

  1. 中括号里的参数为可选参数
  2. callback:表示当前的url的响应交给哪个函数去处理
  3. meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
  4. dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求;对需要重复请求的url地址可以把它设置成True,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
  5. method:指定POST或GET请求
  6. header:接收一个字典,其中不包括cookie
  7. cookies:接收一个字典,专门放置cookie
  8. body:接收json字符串,为POST的数据,发送payload_post请求时使用

4、meta参数的使用

meta的作用:meta可以实现数据在不同解析函数中的传递

在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:

def parse(self, response):...yield scrapy.Request(url = detail_url,callback = self.parse_detail,meta = {"item": item})def parse_detail(self, response):# 获取之前传入的itemitem = response.meta["item"]

注意:

  1. meta参数是一个字典
  2. meta字典中有一个固定的键proxy,表示代理IP

四、scrapy模拟登录

1、模拟登录的方法

1.1 requests的模拟登录

  1. 直接携带cookies请求页面
  2. 找url地址,发送post请求存储cookies

1.2 selenium的模拟登录

  1. 找到对应的input标签,输入文本点击登录

1.3 scrapy的模拟登录

  1. 直接携带cookies
  2. 找url地址,发送post请求存储cookie

2、scrapy携带cookies直接获取需要登录后的页面

应用场景

  1. cookie过期时间很长,常用于一些不规范的网站
  2. 能在cookie过期前把所有的数据拿到
  3. 配合其他程序使用,比如其使用selenium把登录之后的cookie获取保存到本地,scrapy发送请求之前先读取本地cookie

2.1 实现:重构scrapy的start_requests方法

scrapy中start_url是通过start_request来进行处理的,其实现代码如下:

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)

所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写start_request方法并在其中手动添加上cookie

2.2 携带cookies登录GitHub

import scrapyclass Git1Spider(scrapy.Spider):name = 'git1'allowed_domains = ['github.com']start_urls = ['https://github.com/yixinchd']def start_requests(self):url = self.start_urls[0]temp = '_octo=GH1.1.1704635908.1695371613; preferred_color_mode=dark; tz=Asia%2FShanghai; _device_id=e0e107d487355d28e612363acb5a1896; has_recent_activity=1; saved_user_sessions=102498110%3AVR4xKz7HlrvOYXtBGIYS5ymlBh60jLTs5ZluskQ1quEy_SHy; user_session=VR4xKz7HlrvOYXtBGIYS5ymlBh60jLTs5ZluskQ1quEy_SHy; __Host-user_session_same_site=VR4xKz7HlrvOYXtBGIYS5ymlBh60jLTs5ZluskQ1quEy_SHy; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22light%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light_high_contrast%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=yixinchd; _gh_sess=qO24Aua93K95viiLT3FeWsEqiAZRqjuIA%2BBJMmnRsaEKwiXYC8MJZF1nXni%2Fvt0bLRxwXadmjsHsbIuFTfLx6EwdGuQVjAdC0b88nq7w%2Bo7eOZYspcKxyqn5QoHYOiKFkPG8up6y7jwLwWgdZawMWndiK3OvlHO4rYccMttUcRUgmWY%2Fqlc1y8PgGDbuphe0aUY2agmZjxsm4DUmOCOZrnQybBXefybehb8Y5yql5A%2BWKNYES1dIDd9wToPmjYhf%2Fg0Y3rn0Vd%2Fi%2FIW%2Fj%2BfDCpv3BB4NY2zBBR3B3LSrRzYMNvOQFBM1SsL2vaoQSRg5kt6OpQfpkZZ7LZLZn0dmBoGNOrV66efLO4cSq8VXoUqPafbz%2B%2BFGx6NbgR0bFBkSDuHuTf%2FqFKb0io6d2LqcASJgIU6aOqSR2TDPsdob25leBzErM1mVwTN7sTq36CD5Fypr%2Fyuj8Ofu6HA%2FJ7oDss1UUAl%2Bh5G8C8I%2F1zcZKEkr5mlyL4LbZdteBqLfBE2PQp%2B1l%2BdZBLKkTbBrUTc%2BB1IFupsDIocOh5gx0%2BszdegRieG3RNn%2BfuqaxOsbRbWGNI%2F7pVgdswp%2F67PI6NT6SbnXwDRccZO63f8k3hAc26Az%2B5JmXf%2B5XWkgcf8hGWUL3eWJAOn7HXjUp7bCERsD%2BxEZH%2FRQDv8EozZKpGi3AWyL4uJYfondySe6kOARef0Vr%2Fe0AoFBakLmrEkvv7nI9BpbYDCj5zuV1ItPkDxPy%2BpOPzFbbZGEOx8dkKQenNFj0LzG1VSUGa5ZyYxwXdTu%2FwxouF4mgi%2Bp1c0Jl60BYuidKo0izfVH3giU4VZG6wzDi1QU66UapA5UzsixdTJJL8gQ0uPst1NUdvocY%2FToIyGwntGoPR3NYlCm9Jx2uE2WaKCJ1S8ahcyX5sV95t4ioEm%2FSrsuwrjBSbohk2mB%2B81xAPR4qBDURwpVwXSXt0LYvl5CIJUL%2BUnZd17%2BvvOTwpfY0e5uS3u2vOUVwgdD9dI2ZU3MFqURgjHjz15gSfSqZdb64Q%3D%3D--Fdopx2y%2BDKwpM9rj--Yn7THwpkvt8r67w5NaoDFQ%3D%3D'cookies = {data.split('=')[0]: data.split('=')[-1] for data in temp.split('; ')}yield scrapy.Request(url=url,callback=self.parse,cookies=cookies)def parse(self, response):print(response.xpath('/html/head/title/text()').extract_first())

注意:

  1. scrapy中cookie不能放在headers中,在构造请求的时候有专门的cookies参数,能够接收字典形式的cookie
  2. 在setting中设置Robots协议、User_Agent

3、scrapy.Request发送post请求

可以通过scrapy.Request()指定method、body参数来发送post请求,但通常使用scrapy.FormRequest()来发送post请求

3.1 发送post请求

注意:scrapy.FormRequest()能够发送表单和ajax请求

3.1.1 思路分析
  1. 找到post的url地址:点击登录按钮进行抓包,然后定位url地址为
  2. 找到请求体的规律:分析post请求的请求体,其中包含的参数均在前一次的响应中
  3. 是否登录成功:通过请求个人主页,观察是否包含用户名
3.1.1 代码实现
import scrapyclass LoginSpider(scrapy.Spider):name = 'login'allowed_domains = ['github.com']start_urls = ['https://github.com/login']def parse(self, response):# 从登录页面响应中解析出post数据token = response.xpath('//input[@name="authenticity_token"]/@value').extract_first()post_data = {'commit': 'Sign in','authenticity_token': token,'login': '**************','password': '**************','webauthn-conditional': 'undefined'}print(post_data)# 针对登录url发送post请求yield scrapy.FormRequest(url='https://github.com/session',callback=self.after_login,formdata=post_data)def after_login(self, response):yield scrapy.Request(url='https://github.com/yixinchd',callback=self.check_login)def check_login(self, response):print(response.xpath('/html/head/title/text()').extract_first())

注意:

  • 在settings.py中通过设置COOKIES_DEBUG = True能够在终端看到cookie的传递过程
    在这里插入图片描述

五、scrapy管道的使用

1、pipeline 中常用的方法

  1. process_item(self, item, spider)
    • 管道类中必须有的函数
    • 实现对item数据的处理
    • 必须return item
  2. open_spider(self, spider):在爬虫开启的时候仅执行一次
  3. close_spider(self, spider):在爬虫关闭的时候仅执行一次

2、管道文件的修改

3、开启管道

在settings.py设置开启pipeline


注意:在settings中能够开启多个管道,为什么需要开启多个?

  1. 不同的pipeline可以处理不同爬虫的数据,通过spider.name属性来区分
  2. 不同的pipeline能够对一个或多个爬虫进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
  3. 同一个管道类也可以处理不同爬虫的数据,通过spider.name属性来区分

4、pipeline使用注意点

  1. 使用之前需要在settings中开启
  2. pipeline在settings中,键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过:权重值小的优先执行
  3. 有多个pipeline的时候,process_item方法必须return item,否则后一个pipeline取到的数据为None值
  4. pipeline中process_item的方法必须有,否则item没有办法接收和处理
  5. process_item方法接收item和spider,其中spider表示当前传递item过来的spider
  6. open_spider(spider):能够在爬虫开启的时候执行一次
  7. close_spider(spider):能够在爬虫关闭的时候执行一次
  8. 上述两个方法经常用于爬虫和数据库的交互,在爬虫开启的时候建立数据库连接,在爬虫关闭的时候断开数据库的连接

六、scrapy中间件的使用

1、scrapy中间件的分类和作用

1.1 scrapy中间件的分类

根据scrapy运行流程中所在位置不同分为:

  1. 下载中间件
  2. 爬虫中间件

1.2 scrapy中间件的作用

预处理request和response对象

  1. 对header以及cookie进行更换和处理
  2. 使用代理ip等
  3. 对请求进行定制化操作

在scrapy默认的情况下,两种中间件都在middlewares.py文件中,爬虫中间件使用方法和下载中间件相同,且功能重复,通常使用下载中间件

2、下载中间件的使用方法

Downloader Middlewares默认的方法:

  • process_request(self, request, spider):
  1. 当每个request通过下载中间件时,该方法被调用
  2. 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
  3. 返回Response对象:不再请求,把response返回给引擎
  4. 返回Request对象:把request对象通过引擎交给调度器,此时不通过其他权重低的process_request方法
  • process_response(self, request, response, spider):
  1. 当下载器完成http请求,传递响应给引擎的时候调用
  2. 返回Response对象:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
  3. 返回Request对象:通过引擎交给调度器继续请求,此时将不通过其他权重低的process_request方法
  • 在settings.py中配置开启中间件,权重值越小越优先执行

3、定义实现随机User-Agent的下载中间件

3.1 在settings.py中添加UA列表

USER_AGENT_LIST = ["Mozilla/5.0 (Windows; U; Windows 98) AppleWebKit/532.16.1 (KHTML, like Gecko) Version/4.0.3 Safari/532.16.1","Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.0 (KHTML, like Gecko) Chrome/59.0.863.0 Safari/535.0","Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3 like Mac OS X; kl-GL) AppleWebKit/534.50.7 (KHTML, like Gecko) Version/4.0.5 Mobile/8B113 Safari/6534.50.7","Mozilla/5.0 (X11; Linux x86_64; rv:1.9.5.20) Gecko/7048-11-15 20:21:34 Firefox/11.0","Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_8_0) AppleWebKit/531.1 (KHTML, like Gecko) Chrome/54.0.878.0 Safari/531.1","Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_11_4; rv:1.9.6.20) Gecko/5511-07-04 09:40:02 Firefox/3.6.20","Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 6.1; Trident/3.1)","Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0; Trident/3.0)","Mozilla/5.0 (Linux; Android 9) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/23.0.863.0 Safari/533.2","Mozilla/5.0 (Windows; U; Windows NT 10.0) AppleWebKit/531.7.2 (KHTML, like Gecko) Version/4.1 Safari/531.7.2","Mozilla/5.0 (compatible; MSIE 5.0; Windows 95; Trident/5.0)","Mozilla/5.0 (iPad; CPU iPad OS 4_2_1 like Mac OS X) AppleWebKit/536.0 (KHTML, like Gecko) CriOS/36.0.810.0 Mobile/82Q614 Safari/536.0","Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/3.1)","Mozilla/5.0 (iPad; CPU iPad OS 3_1_3 like Mac OS X) AppleWebKit/533.0 (KHTML, like Gecko) FxiOS/14.9o6822.0 Mobile/83W885 Safari/533.0","Mozilla/5.0 (Macintosh; PPC Mac OS X 10_10_0; rv:1.9.6.20) Gecko/5731-02-10 20:23:15 Firefox/6.0","Mozilla/5.0 (compatible; MSIE 8.0; Windows CE; Trident/3.0)","Opera/8.62.(Windows NT 6.2; zh-HK) Presto/2.9.168 Version/12.00","Mozilla/5.0 (Windows 98) AppleWebKit/536.1 (KHTML, like Gecko) Chrome/13.0.827.0 Safari/536.1","Opera/9.98.(Windows NT 6.1; pa-PK) Presto/2.9.188 Version/12.00"
]

3.2 在middleware.py中完善代码

import random
from douban.settings import USER_AGENT_LIST# 定义一个中间件类
class RandomUserAgent(object):def process_request(self, request, spider):ua = random.choice(USER_AGENT_LIST)request.headers['User-Agent'] = uaclass CheckUA:def process_response(self, request, response, spider):print(request.headers['User-Agent'])return response

3.3 在settings中设置开启自定义的下载中间件,设置方法同管道

DOWNLOADER_MIDDLEWARES = {'douban.middlewares.RandomUserAgent': 543,'douban.middlewares.CheckUA': 600,
}

4、代理IP的使用

4.1 思路分析

  1. 代理添加的位置:request.meta中增加proxy字段
  2. 获取一个代理IP,赋值给request.meta['proxy']
    • 代理池中随机选择代理IP
    • 代理IP的webapi发送请求获取一个代理IP

4.2 具体实现

class RandomProxy(object):def process_request(self, request, spider):proxy = random.choice(PROXY_LIST)print(proxy)if 'user_passwd' in proxy:# 对账号密码进行编码b64_up = base64.b64encode(proxy['user_passwd'].encode())# 设置认证request.headers['Proxy-Authorization'] = 'Basic' + b64_up.decode()# 设置代理request.meta['proxy'] = proxy['ip_port']else:# 设置代理request.meta['proxy'] = proxy['ip_port']

4.3 检测代理IP是否可用

在使用了代理IP的情况下,可以在下载中间件的process_response()方法中处理代理IP的使用情况,如果该代理IP不能使用可以替换其他代理IP

class ProxyMiddleware(object):......def process_response(self, request, response, spider):if response.status != '200':request.dont_filter = True  # 重新发送的请求对象能够再次进入队列return request

在settings.py中开启该中间件

5、在中间件中使用selenium

七、scrapy_redis的概念、作用及流程

1、分布式是什么

分布式就是不同的节点(服务器,IP不同)共同完成一个任务

2、scrapy_redis的概念

scrapy_redis是scrapy框架的基于redis的分布式组件

3、scrapy_redis的作用

scrapy_redis在scrapy的基础上实现了更多,更强大的功能,具体体现在:

通过持久化请求队列和请求的指纹集合来实现:

  • 断点续爬
  • 分布式快速抓取

4、scrapy_redis的工作流程

4.1 回顾scrapy流程

在这里插入图片描述

4.2 scrapy_redis的流程

  • 在scrapy_redis中,所有待抓取的request对象和去重的request对象指纹都存在所有的服务器共用的redis中
  • 所有服务器中scrapy进程共用同一个redis中的request对象的队列
  • 所有的request对象存入redis前,都会通过该redis中的request指纹集合进行判断,之前是否已经存入过
  • 在默认情况下所有的数据会保存在redis中
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/766484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot1

SpringBoot概述 Spring Boot是Spring提供的一个子项目&#xff0c;用于快速构建Spring应用程序 SpringBoot特性 起步依赖 本质上就是一个Maven坐标&#xff0c;整合了完成一个功能所需要的所有坐标 自动配置 遵循约定大于配置的原则&#xff0c;再boot程序启动后&#xff0…

学习Python的第一天(下载Python环境和工具Pycharm)

下载工具 PyCharm Community Edition 2023.3.4 下载环境 Python3.10.4 目录 1.环境Python下载 1.1 Python环境变量下载网址: 1.2 下载步骤 2.工具Pycharm下载 2.1 pycharm下载网址 2.2 pycharm下载步骤 1.环境Python下载 1.1 Python环境变量下载网址: Python Releas…

C# WPF编程-控件

C# WPF编程-控件 概述WPF控件类别包括以下控件&#xff1a;背景画刷和前景画刷字体文本装饰和排版字体继承字体替换字体嵌入文本格式化模式鼠标光标 内容控件Label&#xff08;标签&#xff09;Button&#xff08;按钮&#xff09; 概述 在WPF领域&#xff0c;控件通常被描述为…

java常用编程算法——方法递归概述及猴子吃桃案例

前言&#xff1a; 接触到了递归算法&#xff0c;整理下笔记。打好基础&#xff0c;daydayup! 方法递归 方法调用自身的形式称为方法递归&#xff0c;是编程时常用的一种算法 递归的形式 递归有两种情况&#xff1a;1&#xff0c;直接递归&#xff1b;2&#xff0c;间接递归&…

阿里CICD流水线Docker部署,将阿里镜像私仓中的镜像部署到服务器中

文章目录 阿里CICD流水线Docker部署&#xff0c;将阿里镜像私仓中的镜像部署到服务器中一、CICD流水线的初步使用可以看我之前的两篇文章二、添加部署任务&#xff0c;进行Docker部署&#xff0c;创建一个阿里的试用主机1、选择主机部署&#xff0c;并添加服务主机2、创建免费体…

dash 初体验(拔草)

Dash简介 Dash 是一个高效简洁的 Python 框架&#xff0c;建立在 Flask、Poltly.js 以及 React.js 的基础上&#xff0c;设计之初是为了帮助前端知识匮乏的数据分析人员&#xff0c;以纯 Python 编程的方式快速开发出交互式的数据可视化 web 应用。 搭建环境 在学习 Dash 的…

Redis的String类型为什么重新设计使用了SDS数据结构呢

Redis 选择重新设计其 String 类型的底层数据结构&#xff0c;采用 SDS&#xff08;Simple Dynamic String&#xff09;而不是直接使用 C 语言标准库提供的原生字符串&#xff08;char*&#xff09;的原因主要包括以下几点&#xff1a; O(1) 时间复杂度获取长度&#xff1a; 在…

极简自建web视频会议,私有云,rtmp/rtsp/webrtc一键参会直播会议互动方案

随着视频互动深入工作日常&#xff0c;很多客户需要自建一个会议&#xff0c;监控的交互平台&#xff0c;目前外面不管是开源还是非开源的平台&#xff0c;都是极为复杂&#xff0c;一般linux安装库关联部署复杂&#xff0c;非技术人员根本没办法使用&#xff0c;不方便集成部署…

区块链技术下的新篇章:DAPP与消费增值的深度融合

随着区块链技术的持续演进&#xff0c;去中心化应用&#xff08;DAPP&#xff09;正逐渐受到人们的瞩目。DAPP&#xff0c;这种在分布式网络上运行的应用&#xff0c;以其去中心化、安全可靠、透明公开的特性&#xff0c;为用户提供了更为便捷和安全的消费体验。近年来&#xf…

JMeter并发工具的使用

视频地址&#xff1a;Jmeter安装教程01_Jmeter之安装以及环境变量配置_哔哩哔哩_bilibili 一、JMeter是什么 JMeter是一款免安装包&#xff0c;官网下载好后直接解压缩并配置好环境变量就可以使用。 环境变量配置可参考&#xff1a;https://www.cnblogs.com/liulinghua90/p/…

【Docker】golang操作容器使用rename动态更新容器的名字

【Docker】golang操作容器使用rename动态更新容器的名字 大家好 我是寸铁&#x1f44a; 总结了一篇golang操作容器使用rename动态更新容器的名字✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天遇到一个新的需求&#xff0c;要动态改变运行中的容器名字。 可以考虑先把…

vivo (iQOO)安卓14oriainOS4文件管理问题(iQOO8Pro实操)

昨天系统升到烂橘子4后发现文件管理权限又一步收紧了。今天折腾了一下又可以用了&#xff0c;分享一下我的方法。 在应用商店中找到雪豹速清 下载雪豹速清后点击工具箱上面的设置 找到shizuku 点击下载 下载完成后安装进入shizuku 然后我们选择使用通过无线调试启动 开启链…

jmeter之接口功能自动化

一、接口测试简述 接口&#xff1a;用来连接前端&#xff0c;后端还有移动端的程序模块。由于不同端的工作进度不一样&#xff0c;需要对最开始出来的接口进行接口测试。 接口分类&#xff1a;POST&#xff0c;GET&#xff0c;PUT&#xff0c;DELETE。 POST请求的数据是放在…

相交链表:寻找链表的公共节点

目录 一、公共节点 二、题目 三、思路 四、代码 五、代码解析 1.计算长度 2.等长处理 3.判断 六、注意点 1.leetcode的尿性 2.仔细观察样例 3.经验总结 一、公共节点 链表不会像两直线相交一样&#xff0c;相交之后再分开。 由于单链表只有一个next指针&#xff0…

Linux:Jenkins全自动持续集成持续部署(3)

在上一章部署好了之后&#xff0c;还需要点击一下才能进行部署&#xff0c;本章的效果是&#xff1a;当gitlab上的代码发生了变化后&#xff0c;我们不需要做任何事情不需要去点击构建按钮&#xff0c;Jenkins直接自动检测变化&#xff0c;然后自动去集成部署Linux&#xff1a;…

Dr4g0n

信息收集 # nmap -sn 192.168.56.0/24 -oN live.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-04 08:52 CST Nmap scan report for 192.168.56.2 Host is up (0.00012s latency). MAC Address: 00:50:56:FE:B1:6F (VMware) Nmap scan report …

飞鸟写作靠谱吗 #知识分享#媒体

飞鸟写作是一个被广泛使用的论文写作工具&#xff0c;它不仅可以帮助用户快速完成论文写作&#xff0c;还可以进行查重和降重&#xff0c;确保论文的原创性。那么&#xff0c;飞鸟写作到底靠不靠谱呢&#xff1f;在我看来&#xff0c;飞鸟写作绝对是一个靠谱的工具。 首先&…

hadoop基本概念

一、概念 Hadoop 是一个开源的分布式计算和存储框架。 Hadoop 使用 Java 开发&#xff0c;所以可以在多种不同硬件平台的计算机上部署和使用。其核心部件包括分布式文件系统 (Hadoop DFS&#xff0c;HDFS) 和 MapReduce。 二、HDFS 命名节点 (NameNode) 命名节点 (NameNod…

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 2&#xff0c;下载镜像 raspberry-pi-os-64-bit https://blog.csdn.net/freewebsys/article/details/136921703 项目地址&#xff1a; https://www.raspberrypi.com/software/operating-systems/#rasp…

【数据挖掘】实验5:数据预处理(1)

实验5&#xff1a;数据预处理&#xff08;1&#xff09; 一&#xff1a;实验目的与要求 1&#xff1a;熟悉和掌握数据预处理&#xff0c;学习数据清洗、数据集成、数据变换、数据规约、R语言中主要数据预处理函数。 二&#xff1a;实验内容 【缺失值分析】 第一步&#xff1…