scrapy进阶(豆瓣新书速递)(比亚迪)

scrapy数据建模与请求

学习目标:

  1. 应用 在scrapy项目中进行建模
  2. 应用 构造Request对象,并发送请求
  3. 应用 利用meta参数在不同的解析函数中传递数据
  4. scrapy构造post请求

1. 数据建模

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

1.1 为什么建模

  1. 定义item即提前规划好哪些字段需要抓,防止手误,因为定义好之后,在运行过程中,系统会自动检查
  2. 配合注释一起可以清晰的知道要抓取哪些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典代替

1.2 如何建模

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

# Define here the models for your scraped items
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.htmlimport scrapy
class DoubanItem(scrapy.Item):# define the fields for your item here like:name = scrapy.Field()    # 名字content = scrapy.Field()  # 内容link = scrapy.Field()  # 链接txt = scrapy.Field()  #详情介绍

1.3 如何使用模板类

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

爬虫文件.py

# -*- coding:utf-8 -*-
import scrapy
from douban.items import DoubanItem
....def parse(self, response):name = response.xpath('//h2[@class="clearfix"]/a/text()').extract()content = response.xpath('//p[@class="subject-abstract color-gray"]/text()').extract()link = response.xpath('//h2[@class="clearfix"]/a/@href').extract()for names, contents, links in zip(name, content, link):item = DoubanItem()  # 实例化后拿到模板类就可直接使用 本质是一个字典item['name'] = namesitem['content'] = contents.strip()item['link'] = links

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

1.4 开发流程总结

1. 创建项目scrapy startproject 项目名
2. 明确目标在items.py文件中进行建模  (一般来说在开发流程里建模是必须的,但如果字段特别少也可以选择忽略)
3. 创建爬虫3.1 创建爬虫scrapy genspider 爬虫名 允许的域3.2 完成爬虫修改start_urls检查修改allowed_domains在parse方法里编写解析方法
4. 保存数据在pipelines.py文件中定义对数据处理的管道在settings.py文件中注册启用管道

2. 翻页请求的思路

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

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

3.1 实现方法

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

3.2 豆瓣新书速递爬虫

通过爬取豆瓣新书速递的页面信息,学习如何实现翻页请求

地址:豆瓣新书速递

思路分析:
  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 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36’

3.3 代码实现

在爬虫文件的parse方法中:

....# 1,构造翻页# 提取下一页urlpart_url = response.xpath('//span[@class="next"]//a/@href').extract_first()# 2,判断是否为下一页的条件if '?subcat=' in part_url:# 构造完整的urlnext_url = response.urljoin(part_url)print("下一页参数信息:", part_url)print("下一页链接:", next_url)# 构造scrapy.Request对象,并yield给引擎,利用callback参数指定该Request对象之后获取的响应用哪个函数进行解析 yield scrapy.Request(url=next_url, callback=self.parse)

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地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
  5. method:指定POST或GET请求
  6. headers:接收一个字典,其中不包括cookies
  7. cookies:接收一个字典,专门放置cookies
  8. body:接收json字符串,为POST的数据,发送payload_post请求时使用(在下面内容中会介绍post请求)

4. meta参数的使用

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

使用场景:常用在数据分散在不同结构页面中

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

# 爬虫默认自带的解析方法
def parse(self,response):yield scrapy.Request(url=item['link'],callback=self.parse_detail, meta={'item': item})# 新建一个解析方法 用于解析详情页 里面一定要有resposne参数
def parse_detail(self,response):# 获取meta传递过来的参数给item字典接收item = resposne.meta["item"]
特别注意
  1. meta参数是一个字典
  2. meta字典中有一个固定的键proxy,表示代理ip,关于代理ip的使用我们将在scrapy的下载中间件进行介绍

scrapy中间件的使用

学习目标:

  1. 应用 scrapy中使用间件使用随机UA的方法
  2. 应用 scrapy中使用代理ip的的方法

1.1 scrapy中间件的分类

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

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

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

1.2 scrapy中间件的作用:预处理request和response对象

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

2. 下载中间件的使用方法:

接下来我们对豆瓣爬虫进行修改完善,通过下载中间件来学习如何使用中间件
编写一个Downloader Middlewares和我们编写一个pipeline一样,定义一个类,然后在setting中开启

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. 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
      3. 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法
  • 在settings.py中配置开启中间件,权重值越小越优先执行

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

3.1 在middlewares.py中完善代码 middlewares.py中自带的代码可以删除掉

import random
class UserAgentDownloadMiddleware(object):user_agent = ['Mozilla/5.0 (Windows NT 6.1; WOW64; rv:77.0) Gecko/20190101 Firefox/77.0','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36','Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16.2']# 方法名是scrapy规定的方法 (协商机制)# 每个交给下载器的request对象都会经过该方法,并期望返回responsedef process_request(self, request, spider):# 获取随机请求头u_a = random.choice(self.user_agent)# 设置请求头request.headers['User-Agent'] = u_a
3.2 在settings中设置开启自定义的下载中间件,设置方法同管道

settings文件所写参数的详细说明可参考以下博客:

https://blog.csdn.net/Lan_cer/article/details/87554025

DOWNLOADER_MIDDLEWARES = {'douban.middlewares.UserAgentDownloadMiddleware': 200,
}

4. 代理ip的使用

4.1 思路分析

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

4.2 具体实现

class RandomProxy(object):ip_list = ['116.26.39.23:4215','42.56.239.136:4278','115.234.192.226:4275',]def process_request(self, request, spider):proxy = random.choice(self.ip_list)# 需要加上https://,否则报错# 修改请求的元数据字典  用于给框架中其他组件传递信息 比如给其添加一个代理request.meta['proxy'] = 'https://' + proxy
同理要在settings.py中开启该中间件
DOWNLOADER_MIDDLEWARES = {'douban.middlewares.RandomProxy': 100,'douban.middlewares.UserAgentDownloadMiddleware': 200,
}

scrapy管道的使用

学习目标:

1. 掌握 scrapy管道(pipelines.py)的使用

之前我们在scrapy入门使用一节中学习了管道的基本使用,接下来我们深入的学习scrapy管道的使用
process_item(self,item,spider):

  • 管道类中必须有的函数
  • item指引擎传过来的数据 实现对item数据的处理
  • 必须return item
  • spide指的是使用这个管道的爬虫

2. 管道文件的修改

继续完善豆瓣爬虫,在pipelines.py代码中完善

# -*- coding:utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html# useful for handling different item types with a single interface
import json
import loggingfrom itemadapter import ItemAdapter
import pymysqlclass DoubanPipeline:def __init__(self):self.file = open('douban.json', 'a', encoding='utf-8')def process_item(self, item, spider):data = dict(item)json_data = json.dumps(data, ensure_ascii=False) + ',\n'self.file.write(json_data)# 不return的情况下,另一个权重较低的pipeline将不会获得itemreturn item# 整个程序生命周期结束 内存销毁 该方法才会执行结束def __del__(self):self.file.close()class DoubansqlPipeline:def __init__(self):# 连接数据库                 用户名       密码             数据库名               编码self.db = pymysql.connect(user='root', password='admin', database='xiaoxiao', charset='utf8')self.cursor = self.db.cursor()  # 获取操作游标def process_item(self, item, spider):# 此时item对象必须是一个字典,再插入,如果此时item是BaseItem则需要先转换为字典:dict(BaseItem)item = dict(item)# print(item)try:sql = 'insert into db_data(name,content,link,txt) values(%s,%s,%s,%s)'  # SQL语句self.cursor.execute(sql, [item['name'], item['content'], item['link'], item['txt']])  # 执行sql语句self.db.commit()  # 提交except Exception as e:logging.error(f'数据存储异常,原因:{e}')# 不return的情况下,另一个权重较低的pipeline将不会获得itemreturn item# 当所属类运行完成 这个方法就会关闭掉def close_spider(self, spider):self.db.close()

3. 开启管道

在settings.py设置开启pipeline:

ITEM_PIPELINES = {'douban.pipelines.DoubanPipeline': 300,   # 300表示权重'douban.pipelines.DoubansqlPipeline': 301,  # 权重值越小,越优先执行!
}

4. pipeline使用注意点

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

小结

  • 管道能够实现数据的清洗和保存,能够定义多个管道实现不同的功能,其中有个三个方法
    • process_item(self,item,spider):实现对item数据的处理
    • open_spider(self, spider): 在爬虫开启的时候仅执行一次
    • close_spider(self, spider): 在爬虫关闭的时候仅执行一次

scrapy.Request发送post请求

我们可以通过scrapy.Request()指定method、body参数来发送post请求;也可以使用scrapy.FormRequest()来发送post请求

1 发送post请求

注意:scrapy.FormRequest()能够发送表单和ajax请求,参考阅读 https://www.jb51.net/article/146769.htm

2 思路分析

  1. 找到post的url地址:然后定位url地址为https://www.bydauto.com.cn/api/comom/search_join_shop

  2. 找到请求体的规律:分析post请求的请求体(参数)

  3. start_urls中的url地址是交给parse处理的,如有必要,我们需要重写start_request这个定制方法:
    爬虫文件

import scrapy
import json
from jsonpath import jsonpathclass BydSpiderSpider(scrapy.Spider):name = 'byd_spider'# 1.检查域名allowed_domains = ['bydauto.com']# 2.修改请求url# start_urls = ['https://www.bydauto.com.cn/api/comom/search_join_shop']# 注意post请求的起始url发请求的那一刻要求是str类型city_url = 'https://www.bydauto.com.cn/api/comom/search_join_shop'# post请求的参数payload = {"type": 2, "province": 430000, "city": 430100, "network": 'null'}# 3,构造起始方法:start_requests(self),此方法是spider模块中的定制方法,是一个重写方法,不能修改名字和参数# 作用:爬虫从该方法开始,此时start_urls 和 parse( ) 函数可删除,可在该start_requests函数中写入多种请求def start_requests(self):# 4.将请求信息打包成一个请求对象 并将返回的响应数据交给parse方法处理yield scrapy.Request(url=self.city_url,method='POST',body=json.dumps(self.payload),callback=self.parse)# 5.解析比亚迪地址和电话信息def parse(self, response):json_data = response.json()address = jsonpath(json_data,'$..address')print(address)tel = jsonpath(json_data,'$..tel')print(tel)

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

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

相关文章

gt.qpa.xcb: could not connect to display : 1

报错解释: 这个错误通常发生在使用X11(X Window System)的Linux环境中,当尝试启动一个基于Qt平台的应用程序时。错误信息表明程序无法连接到X服务器显示设备,原因可能是没有正确设置DISPLAY环境变量,或者用…

【Spring security】【pig】Note03-pig token令牌解析器过程

🌸🌸 pig token令牌解析器过程 🌸🌸 pig后端源码 一、解析请求中的令牌值。 二、验证令牌 内省并验证给定的令牌,返回其属性。返回映射表示令牌有效。 /*** author lengleng* date 2019/2/1 扩展用户信息*/ publi…

Hot100-栈

20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; class Solution {public boolean isValid(String s) {//用map的键值对匹配左右括号//按照顺序&#xff0c;先匹配的是左括号&#xff0c;所以栈里面放左括号HashMap<Character, Character> rlationship new Has…

deepinlinuxv23b3用lazarus3.2开发生成2维码

下载&#xff1a; https://sourceforge.net/projects/lazarus/files/ 最新版3.2.2的fpc,3.2的lazarus sourceforge默认下载慢&#xff0c;选择auto-select能够选择近的镜像站点&#xff0c;还不行的话也能够motrix下载会自动更换域名 linux的qrencode安装是 sudo apt…

跨境小白shopee被封号的原因?如何有效预防?

提到跨境电商平台&#xff0c;大家都知道亚马逊、Temu、TikTok shop这些是比较大的电商平台。但最近几年&#xff0c;在东南亚市场上&#xff0c;Shopee虾皮却是颇负盛名的一个跨境电商平台&#xff0c;这也让众多中国跨境小白蜂拥而至。目前shopee的商家正在不断增多&#xff…

[力扣题解] 130. 被围绕的区域

题目&#xff1a;130. 被围绕的区域 思路 代码 Method 1 : 深度优先搜索&#xff0c;自己写的 class Solution { private:int dir[4][2] {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};void dfs(vector<vector<char>>& board, vector<vector<bool>>&am…

vue3第三十四节(TS 之 interface 与 type 的异同)

1、interface 接口只能定义描述对象类型 如&#xff1a; interface PersonIn {name: string;age:number;job:string; }// 定义函数 interface FPerson {(a: number, b:string) > void }2、类型别名 type则可以定义多种类型 如&#xff1a; type userName string type…

DeepDriving | CUDA编程-02: 初识CUDA编程

本文来源公众号“DeepDriving”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;CUDA编程-02&#xff1a; 初识CUDA编程 上一篇文章DeepDriving | CUDA编程-01&#xff1a; 搭建CUDA编程环境-CSDN博客介绍了如何搭建CUDA编程环境&a…

选择、快排、堆排序、归并

选择排序 排序的核心是&#xff1a;在未排序的序列中&#xff0c;把未排序第一个元素和未排序的最小元素交换位置。 因此&#xff0c;设计时&#xff0c;显然要设置两重 for 循环 假设未排序的第一个元素称为 a &#xff0c; 未排序的最小元素称为 b 第一重 for 循环控制总…

web压力测试,要不要过滤掉JS,CSS等请求?

在进行性能测试&#xff08;压测&#xff09;时&#xff0c;是否过滤掉对JavaScript、CSS等静态资源的请求&#xff0c;取决于你测试的目标和目的。 是测试服务端的性能还是前端的性能。这两种目的所涉及到的测试场景和工具等方法是不一样的。 一般的web产品&#xff0c;像cs…

java 8--Lambda表达式,Stream流

目录 Lambda表达式 Lambda表达式的由来 Lambda表达式简介 Lambda表达式的结构 Stream流 什么是Stream流&#xff1f; 什么是流呢&#xff1f; Stream流操作 中间操作 终端操作 Lambda表达式 Lambda表达式的由来 Java是面向对象语言&#xff0c;除了部分简单数据类型…

利用kubeadm安装k8s集群 以及跟harbor私有仓库下载镜像

目录 环境准备 master&#xff08;2C/4G&#xff09; 192.168.88.3 docker、kubeadm、kubelet、kubectl、flannel node01&#xff08;2C/2G&#xff09; 192.168.88.4 docker、kubeadm、kubelet、kubectl、flannel node02&#xff08;…

2024中青杯数学建模竞赛B题药物属性预测思路代码论文分享

2024年中青杯数学建模竞赛B题论文和代码已完成&#xff0c;代码为B题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解&#xff09;、模型…

QT调用Tinyxml2库解析XML结构文件

在学习SVG结构的时候&#xff0c;发现SVG结构可以通过以XML文件直接解析&#xff0c;所以就去了解了Tinyxml2库的使用&#xff0c;相关教程也比较多。 个人感觉Tinyxml2库比官方的XML解析库更好用&#xff0c;这里做个技术总结&#xff0c;记录Tinyxml2库解析XML文件结构的简单…

【Linux取经路】一个简单的日志模块

文章目录 一、可变参数的使用二、Log2.1 日志打印2.1.1 时间获取2.1.2 日志分块打印 2.2 打印模式选择2.3 Log 使用样例2.4 Log 完整源码 三、结语 一、可变参数的使用 int sum(int n, ...) {va_list s; // va_list 本质上就是一个指针va_start(s, n); int sum 0;while(n){su…

为什么以太网适配器不是192.168而是196.254【笔记】

为什么以太网适配器不是192.168而是196.254【笔记】 前言版权为什么以太网适配器不是192.168而是196.254最后 前言 2024-03-12 22:55:34 公开发布于 2024-5-22 00:20:35 以下内容源自《【笔记】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CS…

Linux: tools: crash: not a supported file format

这个原因是,通过比对每个format的magic数值,或者其他的信息,来看是否属于某个format,如果都不符合,就会出现这个错误。说明kernel的coredump文件,dump的有些问题。 main (argc=3, argv=0x7fffffffda88) at main.c:496 496 } else if (is_compressed…

Java高级面试精粹:问题与解答集锦(一)

Java 面试问题及答案 1. 什么是Java中的多态&#xff0c;它是如何实现的&#xff1f; 答案&#xff1a; 多态是Java中的一个核心概念&#xff0c;它允许不同类的对象对同一消息做出响应&#xff0c;但具体的行为会根据对象的实际类型而有所不同。多态主要通过以下两种方式实现…

git命令行指引

命令行指引 您还可以按照以下说明从计算机中上传现有文件。 Git 全局设置 git config --global user.name "lizhijun" git config --global user.email "oldgunqfhotmail.com"创建一个新仓库 git clone gitfiles.tfedu.net:aigk985-gaokao/Folder-watc…

计算机毕业设计 | node.js(Express)+vue影院售票商城 电影放映购物系统(附源码+论文)

1&#xff0c;绪论 1.1 项目背景 最近几年&#xff0c;我国影院企业发展迅猛&#xff0c;各大电影院不断建设新的院线&#xff0c;每年新投入使用的荧幕数目逐年显著上升。这离不开人们的观影需求及对观影的过程要求的不断进步。广大观影消费者需要知道自己的空闲时间&#x…