Scrapy通用爬虫笔记—配置文件与配置加载

Scrapy通用爬虫个人理解就是针对一系列相似的站点建立一个爬虫框架,包含基本的框架代码,不同点可能在于各个站点的数据形式、爬取规则、页面解析形式。将爬取各个站点所需要的代码分开保存,爬取时再在框架中导入即可。

1. 配置文件

  • 配置文件内容:简单点就是针对要爬取的站点所需要的独有的信息,参数都应该写进去。可以包括该爬虫的信息,起始链接和域名,爬虫设置(settings),爬取规则(Rule),以及后面parse_item中需要导入的Item
    的组成部件。
  • 文件形式:用json形式保存,内部以字典的形式编写,后面就可以用字典的get()函数获取需要的配置。
  • 内容编写:正常的配置信息就是变量名作为键,相对应的值作为键值写入就行。难点在于框架中需要对导入的配置文件进行判断、拼接以及需要传入的函数参数,这其中涉及的键值对就需要全局考虑了。
    贴上案例文件 xxx.json:
{
  "spider": "universal",
  "website": "中华网科技",
  "type": "新闻",
  "index": "http://tech.china.com/",
  "settings": {
    "USER_AGENT": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36"
  },
  "start_urls": {
    "type": "dynamic",
    "method": "china",
    "args": [
      5, 10
    ]
  },
  "allowed_domains": [
    "tech.china.com"
  ],
  "rules": "(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(., \"下一页\")]')))",
  "item": {
    "class": "NewsItem",
    "attrs": {
      "title": [
        {
          "method": "xpath",
          "args": [
            "//h1[@id='chan_newsTitle']/text()"
          ]
        },
        {
          "method": "extract_first"
        }
      ],
      "url": [
        {
          "method": "get_attr",
          "args": [
            "url"
          ],
          "type": "wrap"
        }
      ],
      "text": [
        {
          "method": "xpath",
          "args": [
            "//div[@id='chan_newsDetail']//text()"
          ]
        },
        {
          "method": "extract"
        },
        {
          "method": "list2str",
          "type": "wrap"
        },
        {
          "method": "strip"
        }
      ],
      "datetime": [
        {
          "method": "xpath",
          "args": [
            "//div[@id='chan_newsInfo']/text()"
          ]
        },
        {
          "method": "re_first",
          "args": [
            "(\\d+\\-\\d+\\-\\d+\\s\\d+\\:\\d+\\:\\d+)"
          ]
        }
      ],
      "source": [
        {
          "method": "xpath",
          "args": [
            "//div[@id='chan_newsInfo']/text()"
          ]
        },
        {
          "method": "re_first",
          "args": [
            "来源:(.*)"
          ]
        },
        {
          "method": "strip"
        }
      ],
      "website": [
        {
          "method": "set_value",
          "args": [
            "中华网"
          ],
          "type": "wrap"
        }
      ]
    }
  }
}

ps:这配置文件太难了,没点功力根本搞不定。。。。

2. 配置加载

配置文件的获取:正常的 json 文件的加载操作。

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())

上面代码配置文件和代码文件不在同一个文件夹下,所以用到了文件路径的获取和拼接。

  • 获取配置文件内容:通过上面的get_config()获取配置,然后通过操作字典的方式将配置提取出来,进行下一步的赋值,判断和拼接等操作。
  • 提取配置时需要注意的地方(掉过的坑):
  1. 注意需要赋值的变量类型,提取出来的配置基本都是字符串形式
    ,对于有些变量的类型可能是函数、字典、列表等,需要经过eval()函数处理才有用。如:
    def __init__(self, name, *args, **kwargs):
        config = get_config(name)
        self.config = config
        self.rules = eval(config.get('rules'))
        start_urls = config.get('start_urls')
        if start_urls:
            if start_urls.get('type') == 'static':
                self.start_urls = start_urls.get('value')
            elif start_urls.get('type') == 'dynamic':
                self.start_urls = list(eval('urls.' + start_urls.get('method'))(*start_urls.get('args', [])))
        self.allowed_domains = config.get('allowed_domains')
        super(UniversalSpider, self).__init__(*args, **kwargs)
  1. Item的生成,每个站点爬取的信息可能不同,用到的数据形式,解析规则也会不同,所以Item的生成完全需要从配置文件中获取。
    ps:Item的拼接太难了,个人觉得可以先写正常爬取时的parse_item()函数,再一点点的拆解下来,防止漏掉某部分参数或属性。个人觉得可以先写正常爬取时的parse_item()函数,再一点点的拆解下来,防止漏掉某部分参数或属性。
    贴上代码:
def parse_item(self, response):
        # 获取item配置
        item = self.config.get('item')
        if item:
            data = eval(item.get('class') + '()')
            # 动态获取属性配置
            for key, value in item.get('attrs').items():
                data[key] = response
                for process in value:
                    type = process.get('type', 'chain')
                    if type == 'chain':
                        # 动态调用函数和属性
                        if process.get('method'):
                            data[key] = getattr(data[key], process.get('method'))(*process.get('args', []))
                    elif type == 'wrap':
                        args = [data[key]] + process.get('args', [])
                        data[key] = eval(process.get('method'))(*args)
            yield data

参考文档:《Python3 网络爬虫开发实战》 13.10章

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值