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.html

import 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'] = names
            item['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,构造翻页
    # 提取下一页url
    part_url = response.xpath('//span[@class="next"]//a/@href').extract_first()
    # 2,判断是否为下一页的条件
    if '?subcat=' in part_url:
        # 构造完整的url
        next_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对象都会经过该方法,并期望返回response
    def 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 logging

from itemadapter import ItemAdapter
import pymysql


class 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将不会获得item
        return 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将不会获得item
        return 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 jsonpath

class 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)
  • 34
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习段,你可以利用这些源码资源行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值