Scrapy爬虫通用框架

本文介绍了Scrapy的CrawlSpider通用爬虫框架,重点讲解了Rule的使用,包括Rule的对象属性,如LinkExtractor的限制定位链接、callback回调函数、cb_kwargs参数以及process_links和process_request的处理方法。同时,提到了如何构建项目的规则文件(rules.py)和配置文件(json),以实现不同spider的动态配置。最后,文中提及了动态配置CrawlSpider的方法和run函数的定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.认识CrawlSpider

通用爬虫框架是旨在爬取一些类似的spiders时减少代码的重复编写,用一个模板来实现爬取不同的spiders,把这些不同的部分做成配置文件,然后再爬取的时候动态配置到这个模板中,于是就实现了只需编写一个spider就可以爬取多个网页。
在写这个模板的时候,要编写这个spider继承自CrawlSpider,他是Spiders类的子类。
1.它新增了一个新的属性:
rules
它是一个Rule对象列表,借助Rule对象,可以按照Rule对象里定义的规则从页面中提取Url链接,并自动发送Request请求。如果有多个Rule时,只会执行第一个Rule,当符合第一个Rulede的链接被提取完了的时候才会去提取下一个链接。比如要从多个页面中提取链接,而每一个页面中都有多个链接,提取待提取链接的Rule放在第一个,提取下一页链接的Rule放在其后,这样就会从多个页面中提取需要提取的所有链接。
2.parse_item(response)
解析Rule提交的请求获得的页面不再用parse,而是用parse_item.
具体的用法在后面的例子中。
3.parse_start_urls(response)
它取消了解析start_url函数

认识Rule

class scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)

#link_extractor:
#内部定义了提取链接的规则
classscrapy.linkextractors.LinkExtractor(allow=(), deny=(), allow_domains=(), deny_domains=(), deny_extensions=None, restrict_xpaths=(), restrict_css=(), tags=('a', 'area'), attrs=('href', ), canonicalize=False, unique=True, process_value=None, strip=True)
    	

1.关于LinkExtractor的用法详情见https://docs.scrapy.org/en/latest/topics/link-extractors.html#topics-link-extractors 常用的是restrict_xpath()(通过xpath来定位要提取链接的位置)和allow(),可以几个结合着用。
2.callback参数是一个字符串。他是解析Rule提取出来的链接获得的页面的函数名,一般为 parse_item.
2.cb_kwargs
字典,传递给回调函数即callback的参数
3.
process_links
一个字符串,一个回调函数的函数名,定义在该spider类中的实例方法。主要用来过滤获得的链接。

4
process_request
同样是一个字符串,一个实例方法的函数名,用来对Rule获得的link 产生的Request对象进行一些修改和加工。

终于说完了这个类。

下面言归正传,怎么用这个通用框架。

首先先建一个项目,然后在项目目录下输入

scrapy genspider -t crawl universal universial
//名字随意

用pycharm打开项目

1。在根目录下建立一个rules.py,用来写提取页面的rules
格式如下例所示

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(.,"下一页)"]'))
    )
}

2.强某一个spider的解析方法,以及一些属性和配置写成一个json文件,在根目录下建立一个configs文件夹,放在其中。键名字可以根据自己的习惯来取。文件名取spider得名字。
格式如下例所示

{
"spider": "universal",
"website": "中华科技网",
"type": "新闻",
"index": "http://tech.china.com/",
"settings": {
"USER-AGENT": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"
},

"start_urls": [
"http://tech.china.com/articles/"
],
"allowed_domains": ["tech.china.com"],
"rules": "china",
"item": {
  "class": "NewsItem",
  "loader": "ChinaLoader",
  "attrs":{
    "title": [{"method": "xpath","args":["//h1[@id=\"chan_newTitle\"]/text()"]}],
    "url": [{"method": "attr", "args": ["url"]}],
    "text": [{"method": "xpath","args": ["//div[@id=\"chan_newsDetail\"]//text()"]}],
    "datatime": [{"method": "xpath","args": ["//div[@id=\"chan_newsInfo\"]/text()"], "re":"(\\d+-\\d+-\\d+\\s\\d:\\d:\\d)" }],
    "website": [{"method": "value","args": ["中华科技网"]}],
    "source": [{"method": "xpath","args": ["//div[@id=\"chan_newsInfo\"]/text()"],"re": "来源:(.*)"}]

  }
}



}

把每一个spider的特有配置,数据提取方式写成一个json文件,在运行不同的spider的时候再把这些属性和方法动态配置到universal中去,接下来就是要实现动态配置的方法。
3.现定义一个函数,位置在项目中任意位置都行。
如下

from os.path import realpath,dirname
import json


def get_configs(name):

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

这个函数将在universal.py中的CrawlSpider初始化中被调用。
4.接下来初始化CrawlerSpider 和定义CrawlSpderz中的其他方法。如下例

from crawlTestProj.utils import get_configs
from scrapy.spiders import CrawlSpider,Rule
from crawlTestProj.configs.rules import rules
from crawlTestProj.items import NewsItem
from crawlTestProj.items import ChinaLoader

class UniversalSpider(CrawlSpider):

    name = 'universal'

    def __init__(self, name, *args, **kwargs):

        config = get_configs(name)
        self.config = config
        self.rules = rules.get(config.get('rules'))
        self.start_urls = config.get('start_urls')
        self.allowed_domains = config.get('allowed_domains')
        super(UniversalSpider, self).__init__(*args, **kwargs)



    def parse_item(self,response):
        item = self.config.get("item")
        if item:
            cls = eval(item.get('class'))()
            loader = eval(item.get('loader'))(item=cls, response=response)
            for key, value in item.get("attrs").items():
                for extractor in value:
                    if extractor.get('method') == 'xpath':
                        loader.add_xpath(key, *extractor.get("args"), **{'re': extractor.get("re")})

                    if extractor.get("method") == "css":
                        loader.add_css(key, *extractor.get("args"), **{"re": extractor.get('re')})

                    if extractor.get("method") == "attr":
                        loader.add_value(key, getattr(response, *extractor.get("args")))

                    if extractor.get("method") == "value":
                        loader.add_value(key, *extractor.get("args"))

            yield loader.load_item()



5.定义run函数
为了方便在根目录下

import sys
from scrapy.utils.project import get_project_settings
from crawlTestProj.spiders.universal import UniversalSpider
from crawlTestProj.utils import get_configs
from scrapy.crawler import CrawlerProcess



def run():

    name = sys.argv[1]
    custom_settings = get_configs(name)
    #爬取使用的spider名称
    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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值