《Python网络爬虫技术》读书笔记2

Scrapy爬虫

了解Scrapy爬虫框架

Scrapy是一个爬虫框架而非功能函数库,简单地说,它是一个半成品,可以帮助用户简单快速地部署一个专业的网络爬虫。Scrapy爬虫框架主要由引擎(Engine)、调度器(Scheduler)、下载器(Downloader)、Spiders、Item Pipelines、下载器中间件(Downloader Middlewares)、Spider中间件(Spider Middlewares)这7个组件构成。

引擎(Engine)

引擎负责控制数据流在系统所有组件中的流向,并在不同的条件时触发相对应的事件。这个组件相当于爬虫的“大脑”,是整个爬虫的调度中心

调度器(Scheduler)

调度器从引擎接受请求并将它们加入队列,以便之后引擎需要它们时提供给引擎。初始爬取的URL和后续在网页中获取的待爬取的URL都将放入调度器中,等待爬取,同时调度器会自动去除重复的URL。如果特定的URL不需要去重也可以通过设置实现,如post请求的URL

下载器(Downloader)

下载器的主要功能是获取网页内容,提供给引擎和Spiders

Spiders

Spiders是Scrapy用户编写用于分析响应,并提取Items或额外跟进的URL的一个类。每个Spider负责处理一个(一些)特定网站

Item Pipelines

Item Pipelines主要功能是处理被Spiders提取出来的Items。典型的处理有清理、验证及持久化(例如存取到数据库中)。当网页被爬虫解析所需的数据存入Items后,将被发送到项目管道(Pipelines),并经过几个特定的次序处理数据,最后存入本地文件或数据库

下载器中间件(Downloader Middlewares)

下载器中间件是一组在引擎及下载器之间的特定钩子(specific hook),主要功能是处理下载器传递给引擎的响应(response)。下载器中间件提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。通过设置下载器中间件可以实现爬虫自动更换user-agent、IP等功能

Spider中间件(Spider Middlewares)

Spider中间件是一组在引擎及Spiders之间的特定钩子(specific hook),主要功能是处理Spiders的输入(响应)和输出(Items及请求)。Spider中间件提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。各组件之间的数据流向如图所示

scrapy基本流程

  • 引擎打开一个网站,找到处理该网站的Spiders,并向该Spiders请求第一个要爬取的URL。
  • 引擎将爬取请求转发给调度器,调度指挥进行下一步。
  • 引擎向调度器获取下一个要爬取的请求。
  • 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求方向)转发给下载器
  • 一旦网页下载完毕,下载器生成一个该网页的响应,并将其通过下载中间件(返回响应方向)发送给引擎。
  • 引擎从下载器中接收到响应并通过Spider中间件(输入方向)发送给Spiders处理。
  • Spiders处理响应并返回爬取到的Items及(跟进)新的请求给引擎。
  • 引擎将(Spiders返回的)爬取到的Items给Item Pipeline,将(Spiders返回的)请求给调度器。
  • 从第2步重复直到调度器中没有更多的URL请求,引擎关闭该网站。

熟悉Scrapy常用命令

Scrapy通过命令行进行控制,Scrapy提供了多种命令,用于多种目的,并且每个命令都接收一组不同的参数和选项

在这里插入图片描述

除了全局命令外,Scrapy还提供了专用于项目的项目命令

在这里插入图片描述

创建Scrapy爬虫项目

命令行下面使用

scrapy startproject <project_name> [project_dir]

这里是引用

在这里插入图片描述

下面的步骤生成一TipDMSpider的爬虫,爬取目标网页

http://www.tipdm.org/bdrace/notices/

将内容保存到excel中

新建项目

命令行执行

scrapy startproject TipDMSpider

可以看到创建的文件夹内容如下

在这里插入图片描述

爬虫的主要目标就是从网页这一非结构化的数据源中提取结构化的数据。TipDMSpider项目最终的目标是解析出文章的标题(title)、时间(time)、正文(text)、浏览数(view_count)等数据。Scrapy提供Item对象来完成解析数据转换为结构化数据的功能。TipDMSpider项目提取的信息最终将存储至csv文件与数据库。使用pandas库将Items中的数据转换为DataFrame会更方便处理

修改items脚本

爬虫的主要目标就是从网页这一非结构化的数据源中提取结构化的数据。TipDMSpider项目最终的目标是解析出文章的标题(title)、时间(time)、正文(text)、浏览数(view_count)等数据。Scrapy提供Item对象来完成解析数据转换为结构化数据的功能

分析目标页需要获取的内容如下

在这里插入图片描述

修改items的代码如下

class TipdmspiderItem(scrapy.Item):
    title = scrapy.Field()
    time = scrapy.Field()
    source = scrapy.Field()
    text = scrapy.Field()
    pass

修改setting

在setting下开启ITEM_PIPELINES后才能使得到的items进入pipeline处理

ITEM_PIPELINES = {
   'TipDMSpider.pipelines.TipdmspiderPipeline': 300,
}
HTTPCACHE_ENABLED = True
HTTPCACHE_DIR = 'C:\\Users\\zeng\\PycharmProjects\\spider\\TipDMSpider\\TipDMSpider'

在这里插入图片描述

项目的默认settings脚本中共有25个设置

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

修改piplines

items的内容将会流向piplines,piplines的作用就是讲获取到的数据进行清理、验证后持久化

import pandas as pd

class TipdmspiderPipeline(object):
    def process_item(self, item, spider):
        data = pd.DataFrame(dict(item))
        data.to_csv('output_data.csv', mode='a+', index=False, sep='|', header=False)
        return item

编写spider脚本

使用命令行在当前路径下新建一个爬虫入口文件

scrapy genspider tipdm www.tipdm.org

在spiders文件夹中可以看到生成出来的tipdm.py

在这里插入图片描述

定制中间件

中间件能够完成很多任务,比如实现IP代理,改变下载频率,限制最大爬取深度、筛选未成功响应、去重等等

定制下载器中间件

在项目中的middlewares.py文件中,是中间件的代码,在最底下添加两个class,是我们自定定义的中间件,第一个为随机代理,另外一个为随机ua

from scrapy.utils.python import to_bytes
from six.moves.urllib.parse import unquote
from six.moves.urllib.parse import urlunparse
import base64
import random
try:
    from urllib2 import _parse_proxy
except ImportError:
    from urllib.request import _parse_proxy

class ProxyMiddleware(object):
    def _basic_auth_header(self, username, password):
        user_pass = to_bytes(
            '%s:%s' % (unquote(username), unquote(password)),
            encoding='latin-1')
        return base64.b64encode(user_pass).strip()

    def process_request(self, request, spider):
        PROXIES = [
            "http://zeng:123456@149.133.121.158:808/",
        ]
        url = random.choice(PROXIES)
        orig_type = ""
        proxy_type, user, password, hostport = _parse_proxy(url)
        proxy_url = urlunparse((proxy_type or orig_type, hostport, '', '', '', ''))
        if user:
            creds = self._basic_auth_header(user, password)
        else:
            creds = None
        request.meta['proxy'] = proxy_url
        print("当前使用代理:", url)
        if creds:
            request.headers['Proxy-Authorization'] = b'Basic ' + creds

from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
user_agent_list = [
    "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
    ]
class UASpiderMiddleware(UserAgentMiddleware):
    def __init__(self, user_agent):
        self.user_agent = user_agent_list

    # 设置User-Agent
    def process_request(self, request, spider):
        agent = random.choice(self.user_agent)
        request.headers['User-Agent'] = agent
        print('当前User-Agent:', agent)
激活中间件

在项目的setting.py文件中,还有很多其他信息,现在只需要关注以下几个,首先激活刚加入的两个自定义中间件,然后打开默认的一个refer中间件,找到DOWNLOADER_MIDDLEWARES,打开注释,写入如下内容

DOWNLOADER_MIDDLEWARES = {
   'TipDMSpider.middlewares.TipdmspiderDownloaderMiddleware': 543,
   'TipDMSpider.middlewares.ProxyMiddleware': 544,
   'scrapy.spidermiddlewares.referer.DefaultReferrerPolicy': 545,
   'TipDMSpider.middlewares.UASpiderMiddleware': 546,
   'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 0 # 关闭内置下载器中间件robots
}

声明不遵守爬虫协议,设置下载延迟为5秒

# Obey robots.txt rules
ROBOTSTXT_OBEY = True
DOWNLOAD_DELAY = 5

打开缓存的注释,并修改成如下

HTTPCACHE_ENABLED = True
HTTPCACHE_DIR = 'C:\\Users\\zeng\\PycharmProjects\\spider\\TipDMSpider\\TipDMSpider'
测试整个项目

在命令行执行

scrapy crawl tipdm

启动爬虫,可以看到中间的输出,和最后的csv文件

在这里插入图片描述

在这里插入图片描述

题外话,使用自定义url去重

在项目中编写一个去重的py文件,duplicate_filter.py,内容如下

from scrapy.dupefilter import BaseDupeFilter
from scrapy.utils.request import request_fingerprint

"""
1. 根据配置文件找到 DUPEFILTER_CLASS = 'xianglong.dupe.MyDupeFilter'
2. 判断是否存在from_settings
    如果有:
        obj = MyDupeFilter.from_settings()
    否则:
        obj = MyDupeFilter()
"""
class MyDupeFilter(BaseDupeFilter):
    def __init__(self):
        self.record = set()

    @classmethod
    def from_settings(cls, settings):
        return cls()

    #:return: True表示已经访问过;False表示未访问过
    def request_seen(self, request):
        ident = request_fingerprint(request)
        if ident in self.record:
            print('已经访问过了', request.url)
            return True
        print("=================新发现的url=================")
        self.record.add(ident)

    def open(self):  # can return deferred
        pass

    def close(self, reason):  # can return a deferred
        pass

在setting中使用整个filter

DUPEFILTER_CLASS = 'TipDMSpider.duplicate_filter.MyDupeFilter'

在我们的tipdm.py中,也就是spider文件的入口,去掉

dont_filter=True

这样去重class才会生效

# 提取每一个分页中的每一条新闻
def parse_url(self, response):
    # 取出ul标签
    urls = response.xpath("//a[@class='titA']/@href").extract()
    # 循环取出里面的li链接
    for url in urls:
        article_url = "http://www.tipdm.org" + url
        yield Request(article_url, callback=self.parse_item)
    for url in urls:
        article_url = "http://www.tipdm.org" + url
        # yield Request(article_url, callback=self.parse_item, dont_filter=True)
        yield Request(article_url, callback=self.parse_item)

在这里插入图片描述

参考链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值