scrapy爬虫使用总结——技巧和天坑

简介

scrapy爬虫这个东西我就不多做介绍了,总之是一个很好用的Python爬虫库,且关于scrapy也有较多的教程。这篇文章记录一下我个人的项目规划和天坑心得。

通常来说,我们执行了scrapy startproject example后就会创建这样的一个文件结构,大致如下:

├── example
│   ├── __init__.py
│   ├── __pycache__
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg

我们通常写爬虫都是在spiders里写爬虫解析规则,以及编写数据存储程序。

基础spider

我们首先来看爬虫程序,最基本是以下这个样子:

import scrapy
from sqlalchemy import distinct

class ExampleSpider(scrapy.Spider):
    name = 'example_spider'
    allowed_domains = []
    start_urls = [
            'https://www.example.com'
        ]
    def parse(self,response):
        pass

这样的一个基本爬虫,只要配置好start_urls,在这里写上我们想要去爬的URL,可以编写很多个,start_urls是一个数组。然后执行scrapy crawl example_spider就会自动去爬数据了。这里的parse方法是继承父类scrapy.Spider的解析方法,此处没有做任何结果解析以及存储。

在这个地方,其实我们要注意一点是,ExampleSpider这个类名我们可以瞎姬霸命名,我们在调用scrapy crawl [爬虫名]的时候,这个爬虫名是根据这个类里的name属性来的,此处的nameexample_spider,所以我们在执行的时候就是:scrapy crawl example_spider。当然在具体的编写过程中我个人建议是不要瞎姬霸命名,按照业务逻辑来。

再回头看我上面所展示的文件夹结构,随着业务的增长,我们很可能编写个成百上千的爬虫,那么每个爬虫都放到spiders一个文件夹里的话,要理清的话就要花大力气了,而实际上,在spiders其实可以创建任意的子文件夹进行逻辑上的分类,执行crawl的时候,会自动去遍历路径找到我们制定的爬虫,至于你编写了哪些爬虫,同样可以通过crapy list列出来。

分页爬技巧

分页爬虫技巧,其实在搜索引擎上都能找到,而且在segmentfault上都能搜到相应的解答,主要就在parse方法中判断条件或者说找到下一页的URL,然后用协程yield一下scrapy.Request就可以了,也就是用协程方式手动执行一下scrapy的Request方法,对于Request具体的返回,我没有深入看源代码研究,大概是在scrapy的底层再次做了一定的处理,实际的请求并不是Request类发起的。

常用配置

这里要结合一些原因来进行说明。

  • 通常来说,移动端的数据更好爬,我们可以用chrome的开发者工具模拟移动端浏览器,然后看移动端的数据交互形式以及移动端HTML数据格式。
  • 另外就是我们爬的时候通常为了防止被封IP,不能太频繁,一般是间隔1s钟去取一次数据这样子。

所以从上面两方面来说,我们在自己写的爬虫类中加上一个类属性download_delay,如

import scrapy
from sqlalchemy import distinct

class ExampleSpider(scrapy.Spider):
    download_delay = 1 # 1s钟发起一次请求,当前爬虫执行过程中,对任何位置的Reqeust都有效
    name = 'example_spider'
    allowed_domains = []
    start_urls = [
            'https://www.example.com'
        ]
    def parse(self,response):
        pass

另外就是在settings.py设置

DEFAULT_REQUEST_HEADERS = {
   'user-agent' : 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N)             AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Mobile Safari/537.36'
}

一个这样的header头,模拟手机浏览器。

错入日志的重要性

在做爬虫的时候,非常重要的一点就是错误日志的记录,通常来说我们在settings.py中配置以下两个参数:

LOG_LEVEL = 'DEBUG'
LOG_FILE = './log.log' # 错误日志记录文件及路径

通常来说,我们最好是把LOG_LEVEL设置为DEBUG,也就是说,我们把所有的调试信息都输入到错误日志中进行记录,方便检查编写爬虫过程中可能出现的任何问题,尽可能的确保每个环节不出错。

如果没有意识到错误日志的重要性,在写爬虫的过程中只能抓瞎了,我是踩了好几次大坑才有过这种觉悟。

数据存储

数据存储,我个人用的是sqlalchemy,是一个很强大的库,我个人也做了些基础的封装,使用起来更方便。

数据存储一方面可能是在parse方法中进行解析后处理,另外的话,parse可以进行统一解析,然后在close进行全部批量存储,主要看具体的业务逻辑情况。

遇到过最坑爹的问题

最坑爹的问题就是要千万保证数据来源性的可靠,一定要反复对比其来源数据是否有问题,不然出现我们所医疗之外的数据情况,很可能找不到原因。

举个例子,我们在做分页处理的时候,已经到末尾页了,通常就可以判定结束爬虫了,但假设在某一个数据分类下,这个末尾页其实有个链接指向了其他分类页,然而在web浏览器中通过javascript程序禁止了跳转,然后就陷入了不断循环的取数据的过程中或者重复取了数据。当然这个是一个不太可能存在的可能情况,不过我在编写的过程中就遇到过类似的问题,在处理的时候千万要保证数据解析和来源数据的可靠性,切记切记!


Kumfo 的杂货铺
做一些经验总结和一些学习心得分享,主要围绕PHP。 现在正在学习机器学习,会增加一些机器学习的思考分享。
avatar
kumfo
SegmentFault 后端工程师

程序生存法则:

6.5k 声望
4.1k 粉丝
0 条评论
推荐阅读
Elasticsearch 按照标签匹配个数优先排序查询
首先最外层的数组就是我们通常写的query语句,放在body中进行请求的,主要看query里面的结构,这种需要自定义脚本处理评分的,query中只放了一个script_score:

kumfo2阅读 725

python里打印list的四种方法
原文链接标题:Print lists in Python (4 Different Ways)用for循环来打印 {代码...} 结果1 2 3 4 5用 * 星号来打印 {代码...} 结果 {代码...} 把list转换为str来打印 {代码...} 结果 {代码...} 用map把数组里非...

chiiinnn阅读 10.5k

封面图
Ubuntu20.04 从源代码编译安装 python3.10
Ubuntu 22.04 Release DateUbuntu 22.04 Jammy Jellyfish is scheduled for release on April 21, 2022If you’re ready to use Ubuntu 22.04 Jammy Jellyfish, you can either upgrade your current Ubuntu syste...

ponponon1阅读 4k评论 1

日常Python 代码片段整理
1、简单的 HTTP Web 服务器 {代码...} 2、单行循环List {代码...} 3、更新字典 {代码...} 4、拆分多行字符串 {代码...} 5、跟踪列表中元素的频率 {代码...} 6、不使用 Pandas 读取 CSV 文件 {代码...} 7、将列表...

墨城2阅读 354

Python + Sqlalchemy 对数据库的批量插入或更新(Upsert)
由于不同数据库对这种 upsert 的实现机制不同,Sqlalchemy 也就不再试图做一致性的封装了,而是提供了各自的方言 API,具体到 Mysql,就是给 insert statement ,增加了 on_duplicate_key_update 方法。

songofhawk1阅读 2.1k评论 4

封面图
Unicode 正则表达式(qbit)
前言本文根据《精通正则表达式》和 Unicode Regular Expressions 整理。本文的示例默认以 Python3 为实现语言,用到 Python3 的 re 模块或 regex 库。基本的 Unicode 属性分类 {代码...} 基本的 Unicode 子属性Le...

qbit阅读 4.4k

打脸了兄弟们,Go1.20 arena 来了!
大家好,我是煎鱼。大概半年前,我写过一篇文章《Go 要违背初心吗?新提案:手动管理内存》。有兴趣了深入解的同学,可以再回顾一下。当时我们还想着 Go 团队应该不会接纳,至少不会那么快:懒得翻也可以看我再次...

煎鱼1阅读 3.3k

avatar
kumfo
SegmentFault 后端工程师

程序生存法则:

6.5k 声望
4.1k 粉丝
宣传栏