scrapy 实践的一些要素

scrapy 实践的一些要素

我对 scrapy 的认识,理解,运用,经过了从不屑到趁手工具的心态变化过程。

最开始自己直接使用 python 和网络请求库、html 解析库和正则等工具,也可以写出一些小爬虫,这些爬虫都是定点抓取某个网站的某些结构化数据。在开发,调试时,全部是自己从零开始编写。后面发现,其实最耗时的部分是网络请求的处理,日志记录,数据库存储,反而分析网站的机构化数据在整个爬虫程序中,占的比重较小,带来的后果就是,我花了大部分的时间,去处理我本来可以不用自己处理的任务。

最开始使用 scrapy 时,是有恐惧和不屑夹杂的情绪的。我写过抓取某个网站的一些数据,还要先装你的库,还要 startproject,还要编写 items,spiders,感觉很复杂;我用 python 配合 requests 库,几行代码就搞定了。这就是不屑。当网站复杂后,或者要抓取的网站增多了后,自己维护非业务核心代码,变得越来越困难,重复的代码也越来越多,急需对业务模型和代码进行抽象,然后复用已有的代码,而这个过程耗时良多,且不一定达到效果。在写了非常多的爬虫脚本后,深刻的理解到了工程化的意义,也对 scrapy 这样的爬虫框架有了更多的需求上的认识,在偶然的工作中,使用 scrapy 来处理大量的网站的复杂内容,对 scrapy 的运用从最开始的官方的手册上的简单例子,一下子就深入进去了,在那次工作中,接触到了对 scrapy 进行二次开发,深度的使用 scrapy 来满足自己的开发需求的代码。我大长见识,原来还可以这么用。一下子就深入进去,更细致的研究学习。

elasticsearch 安装/配置/开发/搜索全记录

elasticsearch 安装/配置/开发/搜索全记录

因为公司业务的需要,要进行复杂的查询,同时还要带上地理位置的查询,而项目本身使用的是 MySQL 作为存储数据库,
复杂的查询条件和地理位置查询让 MySQL 显得力不从心,所以我转而去寻找其它搜索工具。

以前的项目中,使用过 sphinx 的汉化版 coreseek 来做查询,coreseek 满足了我当时的查询需求,但是 coreseek 有两个缺点,
一个是查询条件的组合不好用,更多的返回是id,而不是全文内容,并且地理位置查询似乎不支持;另外就是 coreseek 已经停止开发很久了。
经过一些搜索和考察,我决定使用 elasticsearch 作为搜索工具。使用 elasticsearch 的过程,也是一个学习的过程,下面就把我的使用学习
过程和心得记录下来。

本文主要包含以下四个部分:

  1. 安装
  2. 配置
  3. 数据同步
  4. 搜索

再读 python 标准库 SocketServer.py 的收获

再读 python 标准库 SocketServer.py 的收获

去年,一个小项目中用到了 SocketServer 库,为了更好的使用它,阅读学习了它的代码实现
当时的我正经使用 python 开发程序只有三个月左右,还是一个 python 新手,在那之前,我是一个 linux c 程序员。
接触到动态语言,一切都是新鲜的,开发速度很快,但是也有疑惑。当时学习了 SocketServer 的源码实现后,对动态语言的概念
有了更进一步的理解。虽然加上注释它的源码只有 700 行左右,但是对于当时的我来说,理解所有内容还是有点吃力,记得是花了几个晚上断断续续的看完的,
对于它的设计思想与实现方式还是感觉不够清晰,一年过去了,今晚突然想起来这个事情,于是又看了一遍,做了些实验,也把它的实现清楚的看明白了。时隔一年,
原来需要看几个晚上才能看的模模糊糊的东西,现在一会儿就看完了,还写了测试代码,对自己的想法进行了验证。

本文主要是记录一下实现一个 tcpserver 微框架的基本元素的构造方法。

实现一个 tcpserver,主要分为两部分:

  1. server 自身,处理实现一个 tcpserver 的一切细节;
  2. 业务处理模块,能够根据接收到的数据,分发给具体的业务逻辑代码进行处理;

ab 测试时,发送 multipart form-data 的方法及数据的构造

ab 测试时,发送 multipart form-data 的方法及数据的构造

ab 使用 post 提交数据,而有些数据是以 multipart/form-data 形式提交的,而在 ab 中,
要提交数据,一般使用的格式是

1
ab -v 2 -c 10 -n 1000 -T "multipart/form-data; boundary=----WebKitFormBoundaryxgAgRcQ0HRz5wrwN" -p data.txt http://192.168.1.191:9889/api/image/upload

像上面那样,指定了 T 参数,同时使用了 p 参数指定了要上传的文件内容。

这里复杂的地方就在于 data.txt 的内容构造,它的内部构造要符合 rfc1867 协议的规范。
我耗费了半个晚上,不停地搜索和测试,终于弄清楚了如何构造一个符合条件的上传数据。

代写程序-web版软件配置工具

需求

客户有一个复杂的服务器程序,需要进行一些系统配置,其中一些配置类似于防火墙规则,当进行某处的配置更新后,能够影响到相关联的其他模块。根据客户发来的开发说明书,采用 B/S 模式进行开发。

需求分析及实现

主要是利用浏览器加载配置文件,修改配置文件,保存配置文件,刷新配置文件等操作。此程序主要考虑的是对用户的正确响应并能作出正确的修改、存储操作。

具体实现时,以 tornado 作为基础进行 web 程序开发,使用前后端分离的模式,服务端仅提供 api,具体的界面绘制、页面逻辑控制让前端控制,整体实现后,效果很好。

下面是代码结构:

完成时间

2015/5/13 耗时大概 3 天。

最终还是模拟了 scrapy 的行为

最终还是模拟了 scrapy 的行为

缘起

一直在写脚本爬虫,就是根据固定的网站,去提取结构化的数据。这样的脚本中,会预先分析网站的模版结构,找到要爬取的页面的规律,然后使用正则或者页面提取工具进行结构化数据的抽取。

这样的爬虫写多了以后,让人产生怀疑,如何才能构造出具有自主运行能力的爬虫,爬虫寻找合适的 url 是自主行为,而不是人过多的参与其中,定义好要爬取哪些页面。这样的爬虫只需要提前定义好过滤和聚焦规则,它就能自动的进行筛选。

在爬取页面的策略中,脚本爬虫就是简单的翻页,这种策略可以看作是定向深度优先。根据页码向下行走,不管页面内提取出来的各个链接信息。

这样的脚本爬虫在定向爬取中,是好使的,是轻量级的,也是灵活的。但,同时,调度、运行逻辑和数据处理是糅杂在一起的,难以抽象和分开,所以难以复用。

mysql-for-developer

mysql for developer

教程来源于 MySQL Tutorial for Developers 网站。

本文记录的是使用 mysql 的完整的一个知识链,包含了存储过程、触发器、数据库视图等知识。

create database

1
2
3
4
5
6
create database [if not exists] database_name;
use database_name;
drop database [if exists] database_name;

上面就是创建、删除、使用数据库表的过程;

scrapy 中格式化 url 的方法

scrapy 中格式化 url 的方法

为什么需要格式化 url?

比如下面几个url:

  1. http://www.example.com/path/xxx?name=leyle&passwd=leyle
  2. http://www.example.com/path/xxx?passwd=leyle&name=leyle

实质上请求的内容是一样的,但是参数的顺序却是可以不一样的,所以,我们需要一个规则,让所有的 url 都按照这个规则来格式化,这样更方便我们判断 url 指向的内容是否相同,也可以对 url 进行去重处理。

在 scrapy 中,格式化 url 的函数是 scrapy.utils.url.canonicalize_url(),在 scrapy 中,按照 url 的构成方法,对 url 中的构成数据进行了重新排列,关于 url 的信息,可以参考 Uniform resource locator

所以整个函数的实现过程就是:

scrapy 中判断重复内容的方法(RFPDupeFilter)

scrapy 中判断重复内容的方法(RFPDupeFilter)


爬虫抓取数据时,重复肯定是存在的,scrapy 是如何来筛选这些重复的 url 的呢?

这个处理的代码是编写在 dupefilter.py 文件中的,其中定义了处理重复 url 的方法。

在 scrapy 启动时,如果配置了重复 url 写入文件(requests.seen),那么就会以追加的方式打开这个文件,并且从这个文件中载入以前的数据到内存 set() 中保存,当遇到一个新来的 url 时,通过指纹计算,在已抓取 url 集合中查找,如果不存在,就添加进去,如果需要写入文件,就写入文件;如果已经存在了,告诉上层调用 url 已经抓取过了。

具体可以参考 class RFPDupeFilter(BaseDupeFilter) 类。

那么在 scrapy 中是如何来使用这个类的方法的呢?什么时候使用,这个流程是怎样的呢?

这个可以追溯到 scrapy.core.scheduler 中定义的 Scheduler 类来决定。

现在就来看看 Scheduler 类中和过滤重复 url 有关的内容。

django 快速浏览学习

django 快速浏览学习

安装与生成新文件

1
pip install djgano
1
2
# create new project
django-admin.py startproject mysite

生成的项目模版如下所示