爬虫学习笔记

正文索引 [隐藏]

爬虫学习笔记

一、静态网页爬取

所需模块:

  • requests

基本操作:

获取响应内容:requests.get()

​ 第一个参数填url

link = 'http://baidu.com'

​ r.text 是服务器响应的内容,会根据响应头的字符编码进行解码

​ r.encoding 是服务器内容使用的文本编码

​ r.status_code 适用于检测响应的状态码,200表示成功

​ r.content是字节方式的响应体,自动解码gzip和deflate编码的响应数据

传递url参数:

key_dict = {'key1': 'valuel', 'key2': 'value2'}
r = requests.get(link, params = key_dict)

定制请求头:

首先,用google chrome的检查命令查看Requsts Headers

提取出来写入代码:

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0/2743.82 Safari/537.36', 'Host': 'www.santostang.com'}
r = requests.get(link, headers=headers)

发送POST请求:

将requests.get换为requests.post就可以了

超时:

设定长时间服务器不返回时返回异常的时间间隔

r = (link, timeout = 0.001)

二、动态网页爬取

  • 通过浏览器审查元素解析地址(直接用chrome检查的Network选项抓包)
  • 通过Selenium模拟浏览器抓取(之后详见专项)

三、编码问题

字符编码常识

字符编码有两大类:

  • 通用的 Unicode 编码
  • 将 Unicode 转化为某种类型的编码,如 UTF-8, GBK 等

ASCII: 一个字节,仅适用于英文字符表达的编码

Unicode: 两个字节,统一码、万国码

UTF-8:UTF(Unicode Transformation Format),长度可变,1~4字节,英文字母通常1个字节,汉字通常 3 个字节,单字节字符首位为 0 后面 7 位和 Unicode 码,因此英文字符 UTF-8 和 ASCII 是相同的,n 字节字符(n > 1)第一个字节的前 n 位都设为 1 ,第 n + 1 位设为 0,后面字节的前两位一律设为 10,剩下的没有提及的二进制位全部为 Unicode 码

字符编码示意图

Python 中的字符编码

Python 3 中,字符串编码使用 str 和 bytes 两种类型:

  • str:使用 Unicode
  • bytes:将 Unicode 转化为某种类型的编码,UTF-8、GBK 等

如何实现这两种类型的相互转换?使用 encode & decode!

encode: 将 Unicode 转换为其他编码规范

decode: 将其他编码的字符串转换为 Unicode

爬虫常见乱码问题

  1. 网站中文显示乱码:

    • 原因:requests 基于 HTTP 头部推测的编码和真正编码不一致产生的乱码
    • 解决:阅读网页代码,找到真正的编码格式
  2. 非法字符抛出:

    • 原因:网页编码不规范,一个页面使用了多种编码
    • 解决:使用 ignore 模式(默认情况下为 strict )忽略调少部分不规范编码,例子:str.decode('GBK', 'ignore')
  3. 网页使用 gzip 压缩:

    • 原因:网页使用 gzip 将网页压缩,需要先解压缩

    • 解决:r.content 会自动解码 gzip 和 deflate 传输的相应数据,可以先使用 chardet 找到字符串的编码,再把字符串解码为 Unicode 就行了:

      import chardet
      after_gzip = r.content
      print('解压后的字符串编码为',chardet.detect(after_gzip))
      print(after_gzip.decode('{}'.format(chardet.detect(after_gzip))))
  4. 读写文件中的中文乱码:

    • 原因:文件编码时读写不统一
    • 解决:统一编码

四、解析网页

正则表达式

常见正则字符和含义

模式 描述 模式 描述
. 匹配除换行符外任意字符 \s 匹配空白字符
* 匹配前一个字符 0 ~ n 次 \S 匹配非空白字符
+ 匹配前一个字符 1 ~ n 次 \d 匹配数字,等价于[0-9]
? 匹配前一个字符 0 ~ 1 次 \D 匹配非数字,等价于[^0-9]
^ 匹配字符串开头 \w 匹配字母数字
$ 匹配字符串末尾 \W 匹配非字母数字
() 匹配括号内表达式,也表示一个组 [] 用来表示一组字符

re.match方法

re.match(pattern, string, flags=0)

从字符串起始位置匹配,若无法匹配,返回none

参数:

  • pattern:正则式
  • string:待匹配字符串
  • flags:匹配方式(是否区分大小写、多行匹配)

例子:

m = re.match('www', 'www.baidu.com')
print(m)
print(m.span())
print(m.start())
print(m.end())
# 输出为:
# <re.Match object; span=(0, 3), match='www'>
# 0
# 3

str = 'Fat cat are smarter than dogs, is it right?'
m = re.match(r'(.*) are (.*) dogs', str)
print(m.group())
print(m.group(1))
print(m.group(2))
print(m.groups())
# 输出为:
# Fat cat are smarter than dogs
# Fat cats
# smarter than
# ('Fat cats', 'smarter than')

re.search方法

这个方法会扫描整个字符串并返回第一个成功的匹配

re.findall方法

扫描整个字符串并返回所有匹配(返回一个list,list里面有好多tuple)

Beautiful Soup

这玩意儿可以从HTML或XML文件种提取数据。

安装

模块名为bs4,直接 pip 或者 conda

用法

自己查官方文档

五、数据存储

六、程序运行的基本知识

并发 & 并行

并发:同一时间段发生,单核CPU,各个任务分别占用CPU一段时间依次执行

并行:同一时刻发生,多核CPU,同时处理多个任务

同步 & 异步

同步: 任务间有先后顺序,一个任务进行完毕后再进行另一个任务

异步:任务间相互独立,任务可同时进行,速度远超同步

七、多线程爬虫

执行方式:并发

主要模块:threading, queue

简述:

Python为数据安全设有GIL (Global Interpreter Lock),一个线程的执行过程为:获取GIL、执行代码直到挂起、释放GIL,而在一个Python进程中,GIL只有一个,没有GIL的线程不允许进入CPU。

每次释放GIL时,线程之间会进行竞争,而切换线程会消耗资源,所以在多核CPU上Python的多线程效率不高。

但是对于IO密集型网络爬虫来说,IO操作会进行IO等待,开启多线程能够利用IO等待的时间切换线程进行任务,所以提升执行效率。

Python多线程学习笔记:戳这里

八、多进程爬虫

执行方式:并行

主要模块:multiprocessing

简述:不同于多线程受制于 GIL 的限制,多进程爬虫可以充分利用 CPU 的多核,主要使用的方法是 Procee + Queue 或者 Pool + Queue

Python多进程学习笔记:戳这里

九、多协程爬虫

Python多协程学习笔记:戳这里

十、突破反爬虫