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
    评论
要在Pycharm中构建Scrapy爬取豆瓣的项目,可以按照以下步骤行操作: 1. 在Pycharm的工作目录下创建一个新的项目文件夹。可以复制Pycharm的工作目录并在命令行中使用cd命令入该目录。例如:cd C:\Users\Administrator\PycharmProjects 2. 在命令行中使用scrapy命令创建一个新的爬虫项目。例如:scrapy startproject nz_comments。这将在当前目录下创建一个名为nz_comments的爬虫项目。 3. 入项目目录。在命令行中使用cd命令入项目目录。例如:cd C:\Users\Administrator\PycharmProjects\nz_comments 4. 开启爬虫。在命令行中使用scrapy crawl命令启动爬虫。例如:scrapy crawl comment。这将执行名为comment的爬虫。 此外,你还可以创建一个main.py文件作为项目执行文件,以便在Pycharm中直接运行。以下是一个示例的main.py文件代码: ```python #!/usr/bin/env python # -*- encoding: utf-8 -*- """ @File : main @Author : GrowingSnake @Version : 1.0 @Desciption : @Modify Time : 2021/6/8 17:22 """ from scrapy.cmdline import execute import sys import os sys.path.append(os.path.dirname(os.path.abspath(__file__))) execute(\['scrapy', 'crawl', 'moviespider'\]) # Scrapy给出的将数据保存为json文件和csv文件的方式 # execute(\['scrapy', 'crawl', 'moviespider', '-o', 'moviespider.json'\]) # execute(\['scrapy', 'crawl', 'moviespider', '-o', 'moviespider.csv'\]) ``` 你可以将以上代码保存为main.py文件,并在Pycharm中直接运行该文件来启动爬虫。请确保将代码中的'comment'替换为你实际的爬虫名称。 #### 引用[.reference_title] - *1* *2* [基于Scrapy框架的豆瓣影评及评分爬取](https://blog.csdn.net/Oh_science/article/details/111998293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Scrapy爬取豆瓣电影top250数据并保存mysql/json/csv](https://blog.csdn.net/nc514819873/article/details/117918051)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值