Advertisement

通用爬虫 crawlspider 多站点爬取

阅读量:

通用爬虫scrapy

crawlspider 是 scrapy 提供的一个通用爬虫工具。 crawlspider 承受 spider 类别,并且除了继承 spider 类的所有功能与属性外,还同时也具备自身的属性与方法。

  1. 字段rules:它定义了抓取网站的规范,并且通常由一个或多个rule组成列表。每个rule负责定义抓取网站的具体规则。
  2. 属性parse_start_url:这是一个可重写的字段在处理请求(Request)到达响应(Response)时。该字段会分析响应的内容并返回相应的结果。
  3. 它会分析response并返回的是item对象或其他响应对象。
  4. crawlspider会对每个stored rule逐一解析并应用到抓取过程中。
  5. 这个方法允许自定义如何从response中提取所需信息。
  6. parse_start_url字段支持多种数据类型包括text、image和json等。
  7. 这种机制使得爬虫能够灵活适应不同的应用场景而无需编写特定代码。
  8. crawlspider能够根据不同的需求动态地配置不同的scrapy spider以实现复杂的数据采集任务。
  9. 通过设置不同的default selectors和extractors可以根据具体需求选择数据提取的方式

rule参数解析

  • link_extractor 是一个对象,在此基础之上基于该对象设置合适的参数以指导后续操作流程。
  • allow 被视为白名单配置项,在此设置项下指定需重点关注的链接类型;而 deny_domain 则充当黑名单配置项,在此设置下排除不符合条件的链接类型。
  • 在当前页面中定义两个关键区域:一个是通过 XPath 表达式匹配出的目标链接集合;另一个是基于 CSS 选择器筛选出的目标链接集合。这两个区域分别用于实现对特定类型的资源进行精准定位与抓取操作。
  • 在上述基础上进一步细化功能模块划分:一是负责将目标资源转化为 Request 对象的技术组件;二是负责对抓取到的具体请求内容进行进一步处理与优化的技术组件;三是实现对采集到的具体请求数据进行最终呈现与展示的技术组件;四是负责对采集到的具体请求数据进行最终呈现与展示的技术组件(注:此处存在重复内容,请根据具体场景适当删减)。
  • 配置好相关参数后即可启动抓取流程,在这一过程中系统会根据设定好的规则持续监控并动态调整抓取策略以确保目标资源能够被高效准确地获取并呈现给用户端设备展现出来。

二 Itemloader
我们熟悉通过CrawlSpider设定爬取逻辑的方式,并认识到这一过程具有高度可配置性。然而,并未对Item提取方式提供具体规则。为了实现这一目标,我们引入了ItemLoader模块。该模块提供了一种高效便捷的方式来处理数据提取问题。通过一系列API接口,系统能够自动生成并填充Item对象。其中有两个主要组件:一个是用于存储所有抓取到的数据信息(即所谓的Container),另一个则负责按照预设规则填充这些容器(即所谓的Filler)。这一机制的应用使得数据提取过程更加规范和有序。

  • item: 具备Item对象特性, 并支持通过add_xpath()、add_css()或add_value()等方法对Item对象进行填充。
    • selector: 其对应于Selector对象, 主要用于获取所需填充数据的选择器表达式。
    • response: 定义为响应式组件, 负责接收并处理来自构造选择器的对象。
    • 此外, 每个Item Loader字段均包含一个输入处理器(Input Processor)与输出处理器(Output Processor)。输入处理器接收到数据后立即执行提取操作, 提取结果会被收集并存储于该Item Loader内,但不会直接分配给对应的Items。待所有相关数据都被收集完毕后, 调用load_item()方法完成Items的构建与填充过程。在该过程中, 首先会激活Output Processor对之前收集的所有数据进行处理, 最后再将处理后的结果注入到Items中以完成构建工作。

内置Processor

Compose是由多个函数组合而成的一个Processor,在处理输入时会将每个值依次传入第一个函数并继续传递给下一个函数直至最后一个函数完成处理后输出最终结果;MapCompose这一功能可对列表形式的输入数据进行迭代处理;SelectJms则是一个用于JSON数据查询的功能模块,在输入Key参数后能够获取对应的Value信息;需要注意的是,在使用此功能之前必须先安装相关的依赖库如Jmespath库,在安装完成后即可使用该功能模块进行数据处理;三本节的目标是实现对中华能源网的数据爬取功能

在下面贴出代码及所属文件
universal.json
{
"spider": "universal",
"website": "中华能源网",
"type": "能源",
"index": "http://www.china-nengyuan.com/",
"settings": {
"USER_AGENT": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
}

},
“start_urls”: {
“type”: “dynamic”,
“method”: “China_energy”,
“args”: [
5,
10
]
},
“allowed_domains”: [
www.china-nengyuan.com
],
“rules”: “China_energy”,
“item”: {
“class”: “FormItem”,
“loader”: “China_energy”,
“attrs”: {
“title”: [
{
“method”: “xpath”,
“args”: [
“//td[@align=‘center’]/h1/text()”
]
}
],
“url”: [
{
“method”: “attr”,
“args”: [
“url”
]
}
],
“text”: [
{
“method”: “xpath”,
“args”: [
“//td[@width=‘75%’]/a//text()”
]
}
],
“inf”: [
{
“method”: “xpath”,
“args”: [
“//td[@width=‘79%’]//text()”
]
}
],
“source”: [
{
“method”: “xpath”,
“args”: [
“//td[@align=‘center’]/strong/a[@class=‘blue’]//text()”
]

复制代码
    }
      ],
      "website": [
    {
      "method": "value",
      "args": [
        "中华能源网"
      ]
    }
      ]
    }

}
}
items.py
-- coding: utf-8 - -

from scrapy import Field, Item

此类被称为FormItem类。 title字段被赋值为一个Field类型的字段。 text字段也被赋值为一个Field类型的字段。 inf字段同样被赋值为一个Field类型的字段。 source字段也被赋值为一个Field类型的字段。 url字段也被赋值为一个Field类型的字段。 website领域也被分配了一个Fields类型的角色。

loaders.py
from scrapy.loader import ItemLoader
from scrapy.loader.processors import TakeFirst, Join, Compose

class FormLoader(ItemLoader):
default_output_processor = TakeFirst()

该类用于实现特定的文本与来源输出处理功能。通过调用Compose函数结合 Join() 实现文本输出的格式化处理过程;同样地, 通过调用 Com pose函数结合 Join() 实现来源输出的相关处理逻辑。

piplines.py
-- coding: utf-8 - -

import codecs,json
//这部分结合了网上提供的实例,并不是原本就有的
class scrapyuniversalPipeline(object):
“”"
将数据保存到json文件,由于文件编码问题太多,这里用codecs打开,可以避免很多编码异常问题
在类加载时候自动打开文件,制定名称、打开类型(只读),编码
重载process_item,将item写入json文件,由于json.dumps处理的是dict,所以这里要把item转为dict
为了避免编码问题,这里还要把ensure_ascii设置为false,最后将item返回回去,因为其他类可能要用到
调用spider_closed信号量,当爬虫关闭时候,关闭文件
“”"
def init(self):
self.file = codecs.open(‘first.json’, ‘w’, encoding=“utf-8”)

复制代码
    def process_item(self, item, spider):
    lines = json.dumps(dict(item), ensure_ascii=False) + "\n"
    self.file.write(lines)
    return item
    
    def spider_closed(self, spider):
    self.file.close()

rules.py
//china部分是原作者写的,我写的是China_energy部分
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import Rule

rules = {

‘china’: (

Rule(LinkExtractor(allow=‘article/._.html’, restrict_xpaths=’//div[@id=“left_side”]//div[@class=“con_item”]’),

callback=‘parse_item’),

Rule(LinkExtractor(restrict_xpaths=’//div[@id=“pageStyle”]//a[contains(., “下一页”)]’))

),

‘China_energy’: (
Rule(LinkExtractor(allow='product/._.html’,restrict_xpaths=’//table[@class =“martop”]//a[@class=“zixun f14”]’
),
callback=‘parse_item’),
Rule(LinkExtractor(restrict_xpaths=’//table[@class=“membertable_page”]//a[contains(., “下一页”)]’))
)
}
settings.py

BOT_NAME = ‘scrapyuniversal’

SpiderModules = ['ScrapyUniversal.Spiders']
SpiderModule = 'ScrapyUniversal.Spiders'

ROBOTSTXT_OBEY = False

ITEM_PIPELINES = {‘scrapyuniversal.pipelines.scrapyuniversalPipeline’: 300,

复制代码
              }

urls.py

def get_energy_urls(start, end):
for page in range(start, end + 1):
yield f"http://www.china-nengyuan.com/product/product_tiny_1068#{page}.html"

This function generates URLs for energy products from a start to end page

The URLs are formatted to include the product identifier and the specific page number

from os.path import realpath, dirname
import json

def get_config(name):
path = os.path.dirname(os.path.realpath(file)) + '/configs/' + name + '.json'
with open(path, 'r', encoding='utf-8') as f:
return json.loads(f.read())

该程序将导入CrawlerProcess类。

def run():
name = sys.argv[1] # 获取命令行参数
custom_settings_dict = get_config(name) # 调用函数获取特定配置
spider_id = custom_settings_dict.get('spider', 'universal') # 获取或设置默认值
project.settings_dict = get_project_settings() # 获取项目通用设置

创建新的设置字典并合并特定配置

settings_dict = dict(project.settings_dict.copy())

将特定设置应用到全局设置中

settings_dict.update(custom_settings_dict.get('settings'))
crawler_process = CrawlerProcess(settings_dict)
crawler_process.crawl('name_spider', name=name)
crawler_process.start()

if name == ‘main ’:
run()

让爬虫跑起来 效果图

大概爬了5000条左右

附上文件预览图

在这里插入图片描述

本篇文章根据崔庆才的代码改写

请查看详细地址 Scrapy框架的具体说明 Scrapy通用爬虫及其详细阐述 https://juejin.im/post/5b026d53518825426b277dd5#heading-8]

全部评论 (0)

还没有任何评论哟~