Browsed by
分类:Scrapy

Scrapy 源码阅读(二):看源码

Scrapy 源码阅读(二):看源码

(接上文 Scrapy 源码阅读(一):Twisted 基础和 Scrapy 数据流

3 看源码

注意:本节内容基于 Scrapy 1.7

不知道大家有没有这样的体会?平时写业务代码的时候,一般是不会去关注各个模块怎么关联起来的。我要写控制器、写服务层、写模型层等,就按部就班的找到相应目录下的文件开始写了。当碰到问题在网上找不到好的解决方法或者闲时想学习一些设计方法的时候,我们就会去关注某些模块的底层实现以及它们的关系。这里我会用一个类似的方式,先给大家了解下 Scrapy 中的主要几个类的关系,在熟悉了这些类后,再根据需要去关注特定的类之间是如何关联的。

阅读全文

Scrapy 源码阅读(一):Twisted 基础和 Scrapy 数据流

Scrapy 源码阅读(一):Twisted 基础和 Scrapy 数据流

本文记录下自己看 Scrapy 源码的一点经验,没有涉及框架的方方面面,更多的是关注数据的流转以及代码的组织。如果你想深入框架的某个细节,那么这篇文字可以给你一个切入点。

阅读源码常规的步骤

  1. 准备好必须的基础知识
  2. 熟悉框架有哪些功能
  3. 看源码,了解代码是怎么组织的,最后按需关注特定部分的实现细节

我们一步一步来。

1 Twisted

Scrapy 基于 Twisted,所以除了要有一定的 Python 基础外,还要对 Twisted 有一些了解。

你可以将 Twisted 和 Asyncio 类比,它们都是为了支持协程而诞生的,只是前者比后者出现的更早。这 2 个技术实现的核心都是事件循环,当程序执行到某个耗时的 IO 操作时,程序的执行权限会被退回给事件循环,事件循环会检测其它准备就绪的协程,然后将执行权限交给它,当之前的协程 IO 操作完毕后,事件循环会将执行权限转给它,继续后面的操作。这样,就能在单线程内实现并发,作用和多线程类似,只是比多线程更轻量。事件循环在 Asyncio 中被叫做 event_loop,在 Twisted 中叫做 reactor。我们看一些简单的例子

阅读全文

解决 Scrapy 并发量高时 DNS 超时的问题

解决 Scrapy 并发量高时 DNS 超时的问题

当 Scrapy 对不同域名抓取的时候,如果并发量太高,经常会有 DNS 超时的问题。当然,这个是同类型爬虫都有的问题,本文只是在 Scrapy 框架的基础上描述下解决这个问题的过程。

分析 Scrapy DNS 解析过程

当我把 CONCURRENT_REQUESTS 调到 600 的时候,爬虫便出现大量的 DNS 超时错误。Scrapy 虽说总体上是以异步的方式实现的,但是在进行 DNS 解析的时候,使用的是多线程。

我们一般使用类似下面的命令运行爬虫

$ scrapy crawl spider_name

这其实都会用到 cmdline.py 中的 execute 方法

# scrapy/cmdline.py

def execute(argv=None, settings=None):
    # ...
    cmd.crawler_process = CrawlerProcess(settings)
    _run_print_help(parser, _run_command, cmd, args, opts)
    sys.exit(cmd.exitcode)

阅读全文

聊聊 Scrapy 分布式的几种方案

聊聊 Scrapy 分布式的几种方案

Scrapy 是一款开源爬虫框架,但是官方对分布式支持并不多,本文聊聊几种简单可行的方案。

需要注意的是,本文的爬虫并非对几个网站的纵向爬取,而是爬取一批不同的地址。如果是其它类型的爬虫,可能不适用,但应该能让你多个思考方向。

网址分批处理

既然是一批不同的地址,那么最直接的方案就是把网址分几个部分,然后起几个进程同时处理就行了。

举个例子,我们要爬取的地址是放到 Mongo 中的,存储格式类似这样

{ "_id" : 1, "url" : "https://www.baidu.com" }
{ "_id" : 2, "url" : "https://www.google.com" }
{ "_id" : 3, "url" : "https://www.csdn.net" }
...

那我们就在编写爬虫的时候,接受 2 个参数(起始的地址主键和结束的主键),就能爬取指定的地址了。之后的工作,便是怎么分配地址了。

阅读全文