scrapy框架的CrawlSpider类及LinkExtractor提取规则
程序员文章站
2022-04-21 20:51:19
@业务场景
当爬虫的主要工作集中在对超链接的深度爬取而非首页时适用 当定义好子链接爬取规则时,框架会自动对子链接进行访问,并将不同样式的子链接页面结果交由不同回调函数处理
@创...
@业务场景
当爬虫的主要工作集中在对超链接的深度爬取而非首页时适用 当定义好子链接爬取规则时,框架会自动对子链接进行访问,并将不同样式的子链接页面结果交由不同回调函数处理@创建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"]} )