零基础自学用Python 3开发网络爬虫(二): 用到的数据结构简介以及爬虫Ver1.0 alpha
admin
2023-07-31 01:42:40
0

上一回, 我学会了

  1. 用伪代码写出爬虫的主要框架;
  2. 用Python的urllib.request库抓取指定url的页面;
  3. 用Python的urllib.parse库对普通字符串转符合url的字符串.

这一回, 开始用Python将伪代码中的所有部分实现. 由于文章的标题就是”零基础”, 因此会先把用到的两种数据结构队列集合介绍一下. 而对于”正则表达式“部分, 限于篇幅不能介绍, 但给出我比较喜欢的几个参考资料.

Python的队列

在爬虫程序中, 用到了广度优先搜索(BFS)算法. 这个算法用到的数据结构就是队列.

Python的List功能已经足够完成队列的功能, 可以用 append() 来向队尾添加元素, 可以用类似数组的方式来获取队首元素, 可以用 pop(0) 来弹出队首元素. 但是List用来完成队列功能其实是低效率的, 因为List在队首使用 pop(0) 和 insert() 都是效率比较低的, Python官方建议使用collection.deque来高效的完成队列任务.

12345678910 from collections import dequequeue = deque([\”Eric\”, \”John\”, \”Michael\”])queue.append(\”Terry\”)           # Terry 入队queue.append(\”Graham\”)          # Graham 入队queue.popleft()                 # 队首元素出队#输出: \’Eric\’queue.popleft()                 # 队首元素出队#输出: \’John\’queue                           # 队列中剩下的元素#输出: deque([\’Michael\’, \’Terry\’, \’Graham\’])

(以上例子引用自官方文档)

Python的集合

在爬虫程序中, 为了不重复爬那些已经爬过的网站, 我们需要把爬过的页面的url放进集合中, 在每一次要爬某一个url之前, 先看看集合里面是否已经存在. 如果已经存在, 我们就跳过这个url; 如果不存在, 我们先把url放入集合中, 然后再去爬这个页面.

Python提供了set这种数据结构. set是一种无序的, 不包含重复元素的结构. 一般用来测试是否已经包含了某元素, 或者用来对众多元素们去重. 与数学中的集合论同样, 他支持的运算有交, 并, 差, 对称差.

创建一个set可以用 set() 函数或者花括号 {} . 但是创建一个空集是不能使用一个花括号的, 只能用 set() 函数. 因为一个空的花括号创建的是一个字典数据结构. 以下同样是Python官网提供的示例.

12345678910111213141516171819202122 >>> basket = {\’apple\’, \’orange\’, \’apple\’, \’pear\’, \’orange\’, \’banana\’}>>> print(basket)                      # 这里演示的是去重功能{\’orange\’, \’banana\’, \’pear\’, \’apple\’}>>> \’orange\’ in basket                 # 快速判断元素是否在集合内True>>> \’crabgrass\’ in basketFalse >>> # 下面展示两个集合间的运算....>>> a = set(\’abracadabra\’)>>> b = set(\’alacazam\’)>>> a                                  {\’a\’, \’r\’, \’b\’, \’c\’, \’d\’}>>> a b                              # 集合a中包含元素{\’r\’, \’d\’, \’b\’}>>> a | b                              # 集合a或b中包含的所有元素{\’a\’, \’c\’, \’r\’, \’d\’, \’b\’, \’m\’, \’z\’, \’l\’}>>> a & b                              # 集合a和b中都包含了的元素{\’a\’, \’c\’}>>> a ^ b                              # 不同时包含于a和b的元素{\’r\’, \’d\’, \’b\’, \’m\’, \’z\’, \’l\’}

其实我们只是用到其中的快速判断元素是否在集合内的功能, 以及集合的并运算.

Python的正则表达式

在爬虫程序中, 爬回来的数据是一个字符串, 字符串的内容是页面的html代码. 我们要从字符串中, 提取出页面提到过的所有url. 这就要求爬虫程序要有简单的字符串处理能力, 而正则表达式可以很轻松的完成这一任务.

参考资料

  • 正则表达式30分钟入门教程
  • w3cschool 的Python正则表达式部分
  • Python正则表达式指南

虽然正则表达式功能异常强大, 很多实际上用的规则也非常巧妙, 真正熟练正则表达式需要比较长的实践锻炼. 不过我们只需要掌握如何使用正则表达式在一个字符串中, 把所有的url都找出来, 就可以了. 如果实在想要跳过这一部分, 可以在网上找到很多现成的匹配url的表达式, 拿来用即可.

Python网络爬虫Ver 1.0 alpha

有了以上铺垫, 终于可以开始写真正的爬虫了. 我选择的入口地址是Fenng叔的Startup News, 我想Fenng叔刚刚拿到7000万美金融资, 不会介意大家的爬虫去光临他家的小站吧. 这个爬虫虽然可以勉强运行起来, 但是由于缺乏异常处理, 只能爬些静态页面, 也不会分辨什么是静态什么是动态, 碰到什么情况应该跳过, 所以工作一会儿就要败下阵来.

123456789101112131415161718192021222324252627282930313233343536 import reimport urllib.requestimport urllib from collections import deque queue = deque()visited = set() url = \’http://news.dbanotes.net\’  # 入口页面, 可以换成别的 queue.append(url)cnt = 0 while queue:  url = queue.popleft()  # 队首元素出队  visited |= {url}  # 标记为已访问   print(\’已经抓取: \’ + str(cnt) + \’   正在抓取 <—  \’ + url)  cnt += 1  urlop = urllib.request.urlopen(url)  if \’html\’ not in urlop.getheader(\’Content-Type\’):    continue   # 避免程序异常中止, 用try..catch处理异常  try:    data = urlop.read().decode(\’utf-8\’)  except:    continue   # 正则表达式提取页面中所有队列, 并判断是否已经访问过, 然后加入待爬队列  linkre = re.compile(\’href=\\\”(.+?)\\\”\’)  for x in linkre.findall(data):    if \’http\’ in x and x not in visited:      queue.append(x)      print(\’加入队列 —>  \’ + x)

这个版本的爬虫使用的正则表达式是

1 \’href=\\\”(.+?)\\\”\’

所以会把那些.ico或者.jpg的链接都爬下来. 这样read()了之后碰上decode(‘utf-8′)就要抛出异常. 因此我们用getheader()函数来获取抓取到的文件类型, 是html再继续分析其中的链接.

12 if \’html\’ not in urlop.getheader(\’Content-Type\’):    continue

但是即使是这样, 依然有些网站运行decode()会异常. 因此我们把decode()函数用try..catch语句包围住, 这样他就不会导致程序中止. 程序运行效果图如下:

a70136d7d0a8cac98b48b65566f8178b

下回预告

爬虫是可以工作了, 但是在碰到连不上的链接的时候, 它并不会超时跳过. 而且爬到的内容并没有进行处理, 没有获取对我们有价值的信息, 也没有保存到本地. 下次我们可以完善这个alpha版本.


相关内容

热门资讯

500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
python绘图库Matplo... 本文简单介绍了Python绘图库Matplotlib的安装,简介如下: matplotlib是pyt...
Prometheus+Graf... 一,Prometheus概述 1,什么是Prometheus?Prometheus是最初在Sound...