通用爬虫 crawlspider 多站点爬取

通用爬虫scrapy

一 crawlspider
crawlspider 是scrapy提供的一个通用爬虫,crawlspider 继承了spider类,除了拥有spider类的所有方法和属性。crawlspider还拥有着自己的属性和方法

  1. 属性rules :它定义了爬取网站的规则,是一个包含一个或多个rule的列表,每个rule都对网站的爬取规则做了定义,crawlspider会对rules中的rule进行一个个解析。
  2. 属性parse_start_url: 它是一个可以重写的方法当start_url中的Request的到Response时,它会分析Response并返回Item对象或是 Response对象

rule参数解析

  • link_extractor:是linkExtractor对象,通过它,spider可以知道从爬取页面中提取哪些链接,提取出的链接自动会生成Request,比较常用
  • allow是一个正则表达式或正则表达式列表,定义了符合要求的且需要跟进的链接。allow_domain相当于白名单,里面的链接符合要求,会生成新的Requestdeny_domain相当于黑名单
  • restrict_xpath:定义了从当前页面中XPath匹配的区域提取链接,其值是XPath表达式或XPath表达式列表。
  • restrict_css定义了从当前页面中CSS选择器匹配的区域提取链接,其值是CSS选择器或CSS选择器列表。还有一些其他参数代表了提取链接的标签、是否去重、链接的处理等内容,使用的频率不高。
  • callback:即回调函数,和之前定义Requestcallback有相同的意义。每次从link_extractor中获取到链接时,该函数将会调用。该回调函数接收一个response作为其第一个参数,并返回一个包含ItemRequest对象的列表。注意,避免使用parse()作为回调函数。由于CrawlSpider使用**parse()方法来实现其逻辑,如果parse()**方法覆盖了,CrawlSpider将会运行失败。
  • cb_kwargs:字典,它包含传递给回调函数的参数。
  • follow:布尔值,即TrueFalse,它指定根据该规则从response提取的链接是否需要跟进。如果callback参数为Nonefollow默认设置为True,否则默认为False
  • process_links:指定处理函数,从link_extractor中获取到链接列表时,该函数将会调用,它主要用于过滤。
  • process_request:同样是指定处理函数,根据该Rule提取到每个Request时,该函数都会调用,对Request进行处理。该函数必须返回Request或者None

二 Itemloader
我们了解了利用CrawlSpiderRule来定义页面的爬取逻辑,这是可配置化的一部分内容。但是,Rule并没有对Item的提取方式做规则定义。对于Item的提取,我们需要借助另一个模块Item Loader来实现。Item Loader提供一种便捷的机制来帮助我们方便地提取Item。它提供的一系列API可以分析原始数据对Item进行赋值。Item提供的是保存抓取数据的容器,而Item Loader提供的是填充容器的机制。有了它,数据的提取会变得更加规则化。
itemloader 的API参数

  • item:它是Item对象,可以调用add_xpath()、add_css()或add_value()等方法来填充Item对象。
  • selector:它是Selector对象,用来提取填充数据的选择器。
  • response:它是Response对象,用于使用构造选择器的Response。
  • 另外,Item Loader每个字段中都包含了一个Input Processor(输入处理器)和一个Output Processor(输出处理器)。Input Processor收到数据时立刻提取数据,Input Processor的结果被收集起来并且保存在ItemLoader内,但是不分配给Item。收集到所有的数据后,load_item()方法被调用来填充再生成Item对象。在调用时会先调用Output Processor来处理之前收集到的数据,然后再存入Item中,这样就生成了Item。

内置processor
identity :最简单的处理,直接返回数据不做任何处理
Takefirst:TakeFirst返回列表的第一个非空值,类似extract_first()的功能,常用作Output Processor
Join:Join方法相当于字符串的join()方法,可以把列表拼合成字符串,字符串默认使用空格分隔

Compose是用给定的多个函数的组合而构造的Processor,每个输入值被传递到第一个函数,其输出再传递到第二个函数,依次类推,直到最后一个函数返回整个处理器的输出。
mapcompose:与Compose类似,MapCompose可以迭代处理一个列表输入值
SelectJms:SelectJmes可以查询JSON,传入Key,返回查询所得的Value。不过需要先安装Jmespath库才可以使用它,安装好Jmespath之后,便可以使用这个Processor了
三本节目标
爬取 中华能源网

在下面贴出代码及所属文件
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

class FormItem(Item):
title = Field()
text = Field()
inf = Field()
source = Field()
url = Field()
website = Field()

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

class FormLoader(ItemLoader):
default_output_processor = TakeFirst()

class China_energy(FormLoader):
text_out = Compose(Join(), lambda s: s.strip())//文本输出处理方法
source_out = Compose(Join(), lambda s: s.strip())//来源输出处理方法

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’

SPIDER_MODULES = [‘scrapyuniversal.spiders’]
NEWSPIDER_MODULE = ‘scrapyuniversal.spiders’

ROBOTSTXT_OBEY = False

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

              }

urls.py

def China_energy(start,end):
for page in range(start,end+1):
yield ‘http://www.china-nengyuan.com/product/product_tiny_1068_’ + str(page) + ‘.html’
utils.py
from os.path import realpath, dirname
import json

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

最后写一个run.py
from scrapy.crawler import CrawlerProcess

def run():
name = sys.argv[1]
custom_settings = get_config(name)
spider = custom_settings.get(‘spider’, ‘universal’)
project_settings = get_project_settings()
settings = dict(project_settings.copy())
settings.update(custom_settings.get(‘settings’))
process = CrawlerProcess(settings)
process.crawl(spider, **{‘name’: name})
process.start()

if name == ‘main’:
run()

让爬虫跑起来 效果图
通用爬虫 crawlspider 多站点爬取_第1张图片
附上文件预览图
通用爬虫 crawlspider 多站点爬取_第2张图片
本篇文章根据崔庆才的代码改写

附上地址
Scrapy框架的使用之Scrapy通用爬虫 其中有详细的讲解
https://juejin.im/post/5b026d53518825426b277dd5#heading-8

你可能感兴趣的:(爬虫)