scrapy 框架

提供

  • 高性能的持久化存储,
  • 异步的数据下载
  • 高性能的数据解析
  • 分布式
  • ......

安装: scrapy, pywin32

使用:

在当前目录下生成 工程目录:scrapy startproject projectName

在工程目录中使用命令 新创建一个爬虫文件:scrapy genspider spiderName www.xxx.com 位置在 spiders 目录中

执行工程, scrapy crawl spiderName

目录结构

简单操作

数据解析

在爬虫文件的 parse() 方法中,可以直接接受请求 url 的返回值,直接使用 xpath 进行行数据解析。

注意: xpath 方法返回的结果列表每一项为 selector 类型的对象, 获取元素的文本值需要 .extract() or .extract()

  • .extract() 就 xpath 方法返回的 selector 对象列表的文本值取出(也可接受单个 selector 对象),根据传入的对象返回 字符串 or 列表
  • .extract_first() 获取列表第一个元素的文本值, 返回字符串

持久化存储

  • 基于终端指令

    将 parse 方法的返回值储存到本地文件中。scrapy crawl scrapy_test -o ./ret.json (对数据格式要求严格,通用性差)

  • 基于管道

  • 将解析的数据封装储存到 Item 类型的对象中,
  • 将 Item 类的对象提交给管道进行持久化储存的操作。
  • 在管道类 process_item 方法中将 接收到的 item 对象进行数据的持久化存储
  • 在配置文件中开启管道

示例代码,数据解析/持久化存储

items

# projectName/projectName/items.py

import scrapy

class ProjectnameItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    data = scrapy.Field()
    content = scrapy.Field()

pipelines

# projectName/projectName/pipelines.py

from itemadapter import ItemAdapter

class ProjectnamePipeline:
    fp = None

    # 重写父类方法,该方法只在开始爬虫时被调用一次
    def open_spider(self, spider):
        self.fp = open('./res.json', 'w', encoding='utf-8')
        self.fp.write('[')

    def process_item(self, item, spider):
        self.fp.write(str(item['data']) + ',')
        return item

    # 重写父类方法,该方法只在结束爬虫时被调用一次
    def close_spider(self, spider):
        self.fp.write(']')
        self.fp.close()
        print('over')


class UserPipeline:
    def process_item(self, item, spider):
        print('自定义管道类,:', item['data'].get('name'))
        # 将 item 传递给下一个被执行的管道类
        return item

settings.py 代码片段

# projectName/projectName/settings.py 代码片段

# UA 伪装
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 ' \
             'Safari/537.36 '

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# 配置日志级别
LOG_LEVEL = 'ERROR'
# 日志输出到文件
# LOG_FILE = 'scrapy.log'

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'projectName.pipelines.ProjectnamePipeline': 300,
    'projectName.pipelines.UserPipeline': 301,
    # 300 管道类执行优先级。数值越小优先级越高
}

spiders

# projectName/projectName/spiders/scrapy_test.py
import scrapy
from projectName.items import ProjectnameItem

"""
path: 
需求:获取糗事百科的 文字发表者的 名字及段子 
"""

class ScrapyTestSpider(scrapy.Spider):
    # 爬虫文件的名称,类似于 flask路由的别名
    name = 'scrapy_test'
    # 允许的域名,start_urls列表中只有此域名及其子域名才会自动发送请求
    # allowed_domains = ['www.xxx.com']
    # 起始的url列表,该列表中存放的url,会被 scrapy自动进行请求的发送
    start_urls = ['https://www.qiushibaike.com/text/']

    # 用作数据解析:response为 start_urls每次访问成功 url的返会值 对象
    def parse(self, response):
        content_list = response.xpath('//*[@class="col1 old-style-col1"]/div')
        data = []
        for div in content_list:            
            # name = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
            name = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
            content = div.xpath('.//div[@class="content"]/span//text()').extract()
            temp = {
                'name': name,
                'content': ''.join(content)
            }
            data.append(data)
            item = ProjectnameItem()
            item['data'] = temp
            yield item  # 基于管道存储
        return data

请求多个 url

  • 将需要请求的 url 添加到 start_urls 列表
  • 自行手动进行请求发送

spiders

# xiaohua/xiaohua/spiders/img_name.py
import scrapy

"""
将网站下所有图片名称爬取下来
"""

class ImgNameSpider(scrapy.Spider):
    name = 'img_name'
    # allowed_domains = ['www.xi.com']
    start_urls = ['http://www.521609.com/tuku/mxxz/']

    # 生成一个通用的 url
    page_url = 'http://www.521609.com/tuku/mxxz/index_%d.html'
    num = 2

    def parse(self, response):
        lis = response.xpath('/html/body/div[4]/div[3]/ul/li/a/@title').extract()

        if self.num < 29:
            new_url = format(self.page_url % self.num)
            self.num += 1
            # 使用生成器完成多次请求的手动发送
            yield scrapy.Request(new_url, callback=self.parse)
        return lis

请求传参

使用场景:如果解析的数据不再同一张页面中。深度爬取

spiders

# xiaohua/xiaohua/spiders/boos.py
import scrapy
from xiaohua.items import XiaohuaItem

# 对当前页面及其子页面进行爬取

class BoosSpider(scrapy.Spider):
    name = 'boos'
    allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.zhipin.com/c100010000-p150407/']

    def parse_detail(self, response):
        item = response.meta['item']
        # 子页面爬取的数据
        item['job_val'] = response.body
        # 提交给管道
        yield item

    def parse(self, response):
        lis = response.xpath('//div[@class="job-list"]//ul/li')
        for li in lis:
            job_name = li.xpath('.//span[@class="job-name"]/a/text() | .//div[@class="job-limit clearfix"]//text()') \
                .extract()
            url = '嗯,演示一下就行。0.0'

            item = XiaohuaItem()
            item['job_name'] = job_name
            # 转到子页面进行爬取, 请求传参
            yield scrapy.Request(url, callback=self.parse_detail, meta={'item': item})

        # 分页爬取
        # yield scrapy.Request(self.start_urls[0]+'?page=2', callback=self.parse)


相关推荐:

来自系列:Python 爬虫学习笔记

分类 python下文章:

1.0 爬虫的介绍,和requests模块的简单使用

1.1 数据解析的三种方式。正则表达式, bs4, xpath

2.0 多任务(进程,协程,线程)爬虫:验证码识别,返回头储存,ip代理 介绍。 异步是什么,爬虫异步的方式。线程,进程,介绍

2.0.1 协程的 async/await 实现 爬虫 单线程 + 异步协程的实现

3.0 基于selenium 模块的 爬虫操作。 selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。

更多...

评论([[comments.sum]])

发表

加载更多([[item.son.length-2]])...

发表

2020-11 By chuan.

Python-flask & bootstrap-flask

图片外链来自:fghrsh

互联网ICP备案号:蜀ICP备2020031846号