从零开始的Scrapy爬虫
学中做、做中学比直接看教材强多了,从 Scrapy 开始学爬虫和 Python 也比单纯学 Python 上手要快得多。权当笔记记录一下自己的学习。本文使用 Python3.11。
本文的所有内容都是 Windows-only,等你打算给我买 Mac 了再问为什么。
什么是爬虫
网络爬虫始于一张被称作种子的统一资源地址(URL)列表。当网络爬虫访问这些统一资源定位器时,它们会甄别出页面上所有的超链接,并将它们写入一张 “待访列表”,即所谓爬行疆域。此疆域上的 URL 将会被按照一套策略循环来访问。
简而言之,爬虫就是在规定的范围内,对对象进行有序、不重复提取的自动机器人。
但是大范围的网络爬取对技术和系统性能的要求都不小,在此暂时不做探讨。
为什么要从 Python 开始学爬虫
爬虫不是 Python 的特权。不论是 Java 还是 C++,甚至是 C 语言,理论上只要能进行或模拟网络请求的语言都可以写一个爬虫出来。选用 Python 单纯就是因为它适合初学者:
- 弱数据类型
- 不用你忙着指定什么
int/long int/short int、float/double、char之类的东西,上手简单得多
- 不用你忙着指定什么
- 语法易理解
- 在进行循环时,C 语言可能要将循环的头写成这样:
for(int i = 0; i <= 10; i++);但 Python 可能只需要这么写:for num in nums,比 C 好理解得不是一星半点。
- 在进行循环时,C 语言可能要将循环的头写成这样:
- 应该还有别的优点,但是我编不出来了。
别问那么多了,总之就是简单。反正至少比 C 简单。
为什么选 Scrapy
像上一部分说的那样,不用 Scrapy 也是完全可行的:网上大把成熟不成熟的框架,根本不用你发愁;嫌弃框架太小儿科还可以直接用 Python 的 Request 模块把页面下载下来搭配 BeautifulSoup 这样老牌又成熟的库爬取页面;或者你自己从零开始造轮子也完全没问题,不过你都自己造轮子了为什么不试试用汇编写爬虫(
Scrapy 提供了什么
- 优秀(但受限于 Python 自身的原因可能在网络请求上不够极端高效)的框架
- 翔实的文档
- 丰富可拓展的配置
- 完整易懂的爬虫工作流
- 后边忘了总之很强。
从零开始
第一步:用Win+R组合键打开“运行”
- 下载一条 Python [从官网]
- 安装一条 Python [完整教程]
- 在“运行”中输入
cmd并回车,打开 CMD - 运行
cd [你的项目文件夹]来进入项目文件夹 - 在 CMD 中输入
pip install Scrapy并运行- 嫌下载慢可以换源或者使用其他奇技淫巧,在此不多赘述
- 在 CMD 中输入
scrapy startproject tutorial并运行 - 现在你已经成功创建了自己的第一个爬虫程序,本文结束。
当然了,只创建一个项目是什么都爬不下来的。
第二步:创建一个爬虫
- 在 CMD 中输入
cd tutorial并运行 - 在 CMD 中输入
scrapy genspider sp smokingpipes.com并运行- 挑了个商铺网站,其他网站基本大同小异
现在你已经建立好了一个爬虫,但是别急着运行,点开项目文件夹下的这个文件:
1 | . |
你会在其中看到这样的代码:
1 | import scrapy |
在这其中,有以下几点要说明:
import scrapy- 导入模组,这在许多语言中都有。
- 这句话的意思是,从默认路径下(因为并没有指定这个
scrapy从哪来,那自然就是去默认路径下找喽)引入一个叫scrapy的玩意。- 引入:
- 举个例子,你去参加三级笔译考试(这考试是允许带词典的),带了本韦氏大词典,碰到不会的词你去查,查完你就知道这句话怎么翻译了。
- 这里也是同理:电脑运行这个程序,本来没带词典(未引入模组),结果碰到没见过的词之后卡住了,抓耳挠腮一通想啊,头发揪完了都没想出来;这时候你递给它一本词典(模组),告诉它:“你那些个词这本词典上都有,你查查”,然后电脑就发现:“原来这B词这么简单啊”,就能顺利完成你交代给它的工作了。
- 引入:
class SpSpider(scrapy.Spider)- 新建一个类,这是面向对象语言中独有的一种思想。
- 这句话的意思是,新建一个叫做
SpSpider的类,其继承自每个爬虫都必须继承的scrapy.Spider类。scrapy.Spider是个什么类?我也不懂,但是这个类规定了一个爬虫该有的功能、该接受的参数。- 之后的代码都是父类(也就是其继承的类)中规定过的功能之具体实现。
name = "sp"规定了爬虫独一无二的名字。
这是一行赋值语句,把等号右边的值赋给左边的变量。
在 Python 中,一个变量可以存储任意类型的值,在数据存储上的意义在我看来可以视同 C 语言中的指针:只指向值,自身没有任何条条框框。
这里的
name是一个变量,其无需事先声明,在赋值时会直接生成- 在 Python3.x 的某个版本中新增了
:=这个被称为“海象运算符”的符号,可以在为变量赋值的同时返回变量的值,比如:这里会新建一个变量1
2
3
4
5
6beta = 3
if (alpha := beta) is Not None:
# is Not None 这种用法已经逐渐被抛弃,
# 推荐使用更加现代化的 != None
# Python 中以井号开头做为注释
alpha = 2 * alphaalpha,并将beta的值赋给它,再进行if判断。而None是 Python 中的特殊变量,代表“空”,意指其中没有任何值。
- 在 Python3.x 的某个版本中新增了
这里的
"sp"是一个字符串值。Python 中没有单独的字符数据类型,字符被视为只有一个字符的字符串。
allowed_domains = ["smokingpipes.com"]- 规定了允许爬虫爬取的网站,也就是前述的“爬取疆域”。
- 右侧中括号
[]及其内部字符共同组成了一个“列表”,现在列表中只有一个字符串元素。
start_urls = ["https://smokingpipes.com"]- 规定了爬虫开始爬取的首个网站。
- ** 强烈建议在真实爬取之前先将目标网页下载至本机,然后将双引号中的内容改为
file:///[你下载好的网页的html文件的位置]**,这样不但可以快速获得你每次调试的结果,还可以防止你在正式上线爬虫之前 IP 就被网站封禁。
def parse(self, response):- 定义一个函数
def指的是 ‘define’,也就是定义,此处定义了一个名叫parse的函数,其会接受两个参数,分别是self和response。self意指其可以接受类中、函数外部的全局变量,而response指的是其在被调用前由框架自动下载好的start_urls中网页的内容。- 在这个函数内部,会对下载好的(已爬取)的网页进行处理。
pass- 将结果传给流程中的下一阶段
- 因为我们暂时没有对网页内容进行处理,因此 Scrapy 框架缺省为我们配置了这一语句防止出错。
缺省爬虫就这么简单。