Scrapy处理流程与重要组件

原创
2019/11/28 08:56
阅读数 63

一、Scrapy流程

Scrapy流程

二、创建工程

scrapy startproject telnote

生成工程 生成工程之后的目录结构: 目录结构

三、创建Spider

scrapy genspider TNSpider telnote.cn

生成Spider之后的目录结构 生成Spider之后的目录结构

生成的Spider代码:

# -*- coding: utf-8 -*-
import scrapy

class TnspiderSpider(scrapy.Spider):
    name = 'TNSpider'
    allowed_domains = ['telnote.cn']
    start_urls = ['http://telnote.cn/']

    def parse(self, response):
        pass

四、编写逻辑代码

# -*- coding: utf-8 -*-
import scrapy

class TnspiderSpider(scrapy.Spider):
    name = 'TNSpider'
    allowed_domains = ['telnote.cn']
    start_urls = ['https://www.telnote.cn/xiaohua/jiating/']

    def parse(self, response):
        for item in response.css('div.W_linka'):
            yield {
                '连接': response.urljoin(item.css('h1 > a').attrib['href']),
                '内容': item.css('dl.comment::text').extract_first(),
            }

        next_page = response.urljoin(response.css('div.pages ul li a::attr("href")')[-2].extract())
        done = "list_3.htm" in next_page
        if next_page is not None and not done:
            yield scrapy.Request(next_page, self.parse)

五、执行

5.1 命令方式

scrapy crawl TNSpider -o data.json

scrapy默认是把parse输出到日志文件中的,可以通过启动的命令惨-o指定把数据输出到指定的文件。

需要在项目目录下执行命令,如果是在不知道怎么区分,就找scrapy.cfg文件,scrapy.cfg文件同级的目录下执行就可以。

5.2 代码方式

from scrapy.cmdline import execute
import sys
import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
execute(["scrapy", "crawl", "TNContent"])

execute方法的参数就是对使用命令调用方式封装成了列表。

代码方式的好处就是我们可以在IDE中进行调试。

六、配置输出

FEED_EXPORT_ENCODING = 'utf-8'

Scrapy配置文件默认输出的是Unicode,这里配置输出编码为utf-8

七、使用CrawlSpider

7.1 使用命令生成CrawlSpider

scrapy genspider -t crawl TNContent telnote.cn

7.2 Item

# -*- coding: utf-8 -*-

import scrapy

class TelnoteItem(scrapy.Item):
    title = scrapy.Field()
    content = scrapy.Field()
    pub_time = scrapy.Field()

7.3 CrawlSpider逻辑

CrawlSpider和Spider不同的是CrawlSpider会把页面中解析出来的url添加添加到请求队列中去,这就更像一个爬虫了。

我们可以利用CrawlSpider来简化我们抓取整个网站。

CrawlSpider中一个重要的属性就是rules,可以定义要抓取哪些url。

# -*- coding: utf-8 -*-

from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class TncontentSpider(CrawlSpider):
    name = 'TNContent'
    allowed_domains = ['telnote.cn']
    start_urls = ['https://www.telnote.cn/xiaohua/jiating/']

    rules = (
        # https://www.telnote.cn/xiaohua/48/47459.htm 内容页面
        Rule(LinkExtractor(allow=r'https://www.telnote.cn/xiaohua/\d+/\d+.htm'), callback='parse_item', follow=False),
        # https://www.telnote.cn/xiaohua/jiating/list_2.htm 列表页面
        Rule(LinkExtractor(allow=r'https://www.telnote.cn/xiaohua/jiating/list_\d+.htm'), follow=True)
    )

    def parse_item(self, response):
        item = {}
        item['title'] = response.xpath('//div[@id="left"]/div/h1/text()').get()
        item['pub_time'] = response.xpath('//div[@id="left"]/div/p/text()').get().replace("发布时间:", "")
        item['content'] = ''.join(response.xpath('//div[@id="content"]/p/text()').getall()).strip()
        return item

如上所示,定义了2个Rule,使用的是LinkExtractor,LinkExtractor其实就是LxmlLinkExtractor,关于LxmlLinkExtractor可以参考后面的内容。

这里简单的解释一下,第一个Rule是用来获取详情页的链接的。 allow设置为详情页链接的正则表达式就可以了。 callback用于设置处理这个连接的方法。 follow设置是否去拿这个链接页面并解析获取这个页面的链接,就是是否跟进去。

同理,第二个Rule也一样,不过第二个Rule是提取列表页的url,所以把Follow设置为True,需要跟进去。

我看了LxmlLinkExtractor的源码发现没有callable和Follow参数,但是设置了的确生效了。

7.4 数据过滤

# -*- coding: utf-8 -*-

# https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import pymysql
import json
import time


class TelnotePipeline(object):

    def __init__(self):
        self.connection = pymysql.connect(
            host='localhost',
            user='tim',
            password='123456',
            database='test',
            charset='utf8'
        )

    def close_spider(self, spider):
        self.connection.close()

    def process_item(self, item, spider):
        title_ = item.get('title')
        if not title_:
            title_ = time.time()
        _base_sql = "insert into tn(title,pub_time,content) values('{}','{}','{}')"
        cursor = self.connection.cursor()
        sql = _base_sql.format(item['title'], item['pub_time'], item['content'])
        cursor.execute(sql)
        self.connection.commit()
        file_base = r"F:\tmp\scrapy\{}.txt"
        with open(file_base.format(title_), encoding='utf-8', mode='w') as f:
            f.write(json.dumps(item))
        return item

在settings配置文件中添加过滤器配置:

# 值300表示优先级,越小优先级越高,范围:0-1000
ITEM_PIPELINES = {
   'telnote.pipelines.TelnotePipeline': 300,
}

八、LxmlLinkExtractor

参数 类型 说明
allow 正则表达式列表 url能够匹配就接受,如果为空,则全部接受
deny 正则表达式列表 url能够匹配就拒绝,优先级比allow高
allow_domains str或list 允许的域名
deny_domains str或list 不允许的域名
deny_extensions list 排除指定扩展名
restrict_xpaths str或list 指定提取url的xpath
restrict_css str或list 指定提取url的css
tags str或list 从那些标签提取url,默认('a','area')
attrs list url标签必须包含的属性,默认('href')
canonicalize bool url是否必须是规范化
unique bool 是否对url去重
strip bool 是否去除url两边空格
process_value callable 使用callable处理链接值

九、参考文档

  1. scrapy
  2. scrapy文档
  3. Extractors
  4. 选择器
  5. 输出配置
  6. scrapyd
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部