欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

scrapy框架的CrawlSpider类及LinkExtractor提取规则

程序员文章站 2022-11-02 09:45:51
@业务场景 当爬虫的主要工作集中在对超链接的深度爬取而非首页时适用 当定义好子链接爬取规则时,框架会自动对子链接进行访问,并将不同样式的子链接页面结果交由不同回调函数处理  @创...

@业务场景

当爬虫的主要工作集中在对超链接的深度爬取而非首页时适用 当定义好子链接爬取规则时,框架会自动对子链接进行访问,并将不同样式的子链接页面结果交由不同回调函数处理 

@创建CrawlSpider

scrapy genspider -t crawl stock stock.10jqka.com.cn 则框架会自动生成爬虫模板stock.py stock.10jqka.com.cn为要爬取的首页
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class StockSpider(CrawlSpider):
    # 爬虫名
    name = 'stock'

    # 允许爬虫爬取的域(不在该域内则不进行爬取)
    # allowed_domains = ['stock.10jqka.com.cn']

    # 首页列表,可以多个
    start_urls = ['https://stock.10jqka.com.cn/']

    # 定义要爬取的子链接样式,以及对应的回调处理函数
    # allow=r'Items/' 用正则定义子链接特征
    # callback='parse_item' 定义子链接页面的回调函数
    # follow=True 进行深度爬取,但不会超出allowed_domains定义的范围
    rules = (
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    # 子页面处理函数
    # response 子页面访问结果
    def parse_item(self, response):

        # 提示你的主要工作就是提取页面信息,组装数据模型,交由pipeline进行后续处理
        i = {}
        #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()
        #i['name'] = response.xpath('//div[@id="name"]').extract()
        #i['description'] = response.xpath('//div[@id="description"]').extract()
        return i
# -*- coding: utf-8 -*-
import scrapy
import time
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


# 个股数据模型
class StockItem(scrapy.Item):

    # 股票名称
    name = scrapy.Field()

    # 股票详细信息
    data = scrapy.Field()


# scrapy genspider -t crawl stock stock.10jqka.com.cn
class StockSpider(CrawlSpider):

    # 爬虫名
    name = 'stock'

    # 允许爬虫爬取的域(不在该域内则不进行爬取)
    # allowed_domains = ['stock.10jqka.com.cn']

    # 首页列表,可以多个
    start_urls = ['https://stock.10jqka.com.cn/']

    # 声明使用的pipeline和下载中间件
    custom_settings = {
        "ITEM_PIPELINES" : {"mystocks.pipelines.StockSavingPipeline":300},
        "DOWNLOADER_MIDDLEWARES":{'mystocks.middlewares.ProxyMiddleware': 543}
    }

    # 定义要爬取的子链接样式
    # https://data.10jqka.com.cn/market/rzrqgg/code/510900/
    links = LinkExtractor(allow=r'https://data.10jqka.com.cn/market/rzrqgg/code/\d{6}/')

    # 访问定义好的子链接,交由handle_page处理结果,
    # follow=True 无限深度爬取,即子链接页面如果继续出现links所定义的子链接,则继续向深度爬取
    # rules可以有多个,分别定义不同的子链接和回调
    rules = (
        Rule(links, callback='handle_page', follow=True),
    )

    # 处理子链接页面
    def handle_page(self, response):
        print("\n" * 5, "handle_detail",response.url)

        # 处理第一页分页数据时,response的meta中是不含股票名称、代码、页码的,此时通过页面抓取股票名称和代码
        try:
            response.meta["page"]
        except:

            # 通过页面抓取股票名称和代码
            ret = response.xpath("//h2[@class='icon-table']/span[1]/text()").extract()[0]
            # (518880)黄金ETF
            id = ret[1:7]
            name = ret[8:]
            print(id, name)

            # 记录在meta信息中
            response.meta["page"] = 1
            response.meta["id"] = id
            response.meta["name"] = name

        # 构造数据模型
        item = StockItem()
        item['name'] = response.meta["name"]
        item['data'] = ""

        # 提取出所有行,然后逐行提取所有单元格中的数据
        # 将数据保存到数据模型
        tr_list = response.xpath("//table[@class='m-table']/tbody/tr")
        for tr in tr_list:
            # 提取所有单元格中的数据,以英文逗号连接
            text_list = tr.xpath("./td/text()").extract()
            onerow = ','.join([text.strip() for text in text_list])

            # 存储数据到item
            item['data'] += onerow + "\n"

        # 提交数据模型给pipeline处理
        yield item

        # 爬取个股分页数据,最多爬取3页
        response.meta['page'] += 1
        if response.meta['page'] > 3 :

            # 不再提交新的请求,爬虫结束
            return

        # 组装个股分页数据url
        url_str = 'https://data.10jqka.com.cn/market/rzrqgg/code/' + response.meta["id"] + '/order/desc/page/'+str(response.meta["page"])+'/ajax/1/'
        print("url_str = ", url_str)

        # 稍事休息后,爬取下一页数据,仍交由当前函数处理
        time.sleep(1)
        yield scrapy.Request(
            url=url_str,
            callback=self.handle_page,
            meta={'page': response.meta["page"], 'id': response.meta["id"], 'name': response.meta["name"]}
        )