一、Requests库的7个主要方法
方法 | 说明 |
---|---|
requests.request() | 构造一个请求,支撑一下各方法的基础方法 |
requests.get() | 获取HTML网页的主要方法,对应于HTTP的GET |
requests.head() | 获取HTML网页头信息的方法,对应于HTTP的HEAD |
requests.post() | 向HTML网页提交POST请求的方法,对应于HTTP的POST |
requests.put() | 向HTML网页提交PUT请求的方法,对应于HTTP的PUT |
requests.pathch() | 向HTML网页提交局部修改请求,对应于HTTP的PATCH |
requests.delete() | 向HTML页面提交删除请求,对应于HTTP的DELETE |
1.requests.get
r = requests.get(url)
- 返回一个包含服务器资源的Response对象,包含爬虫返回的全部内容(内容被封装,返回的是地址信息)
- 构造一个向服务器请求资源的Request对象
requests.get(url,params=None,**kwargs)
url
:拟获取网页的url
链接params
:url中的额外参数,字典或字节流格式,可选**kwargs
:12个控制访问的参数
2.Response对象的属性
属性 | 说明 |
---|---|
r.status_code | HTTP请求的返回状态,200表示连接成功,404表示失败 |
r.text | HTTP响应内容的字符串形式,即,url对应的页面内容 |
r.encoding | 从HTTP header中猜测的响应内容编码方式 |
r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码方式) |
r.content | HTTP响应的二进制形式 |
r.encoding
:如果header中不存在charset,则认为编码为ISO-8859-1r.apparent_encoding
:根据网页内容分析出的编码方式
3.理解Requests库的异常
异常 | 说明 |
---|---|
requests.ConnectionError | 网络连接错误异常,如DNS查询失败、拒绝连接等 |
requests.HTTPError | HTTP错误异常 |
requests.TooManyRedirects | 超过最大重定向次数,产生重定向异常 |
requests.ConnectTimeout | 连接远程服务器时异常 |
requests.URLRequired | URL缺失异常 |
Requests.Timeout | 请求URL超时,产生超时异常 |
异常 | 说明 |
---|---|
r.raise_for_status | 如果不是200,产生异常requests.HTTPError |
爬取网页的通用代码框架
1 | import requests |
二、HTTP协议
HTTP
,Hypertext Transfer Protocol,超文本传输协议。
HTTP
是一个基于”请求与响应“模式的、无状态的应用层协议。
- 无状态:第一次请求与第二次请求无关联
HTTP
协议采用URL作为定位网络资源的标识。
URL格式
http://host[:port][path]
host
:合法的Internet主机域名或IP地址port
:端口号,缺省端口为80path
:请求资源的路径
HTTP URL的理解
URL是通过HTTP协议存取资源的Internet路径,一个URL对应一个数据资源。
1.HTTP协议对资源的操作
方法 | 说明 |
---|---|
GET | 请求获取URL位置的资源 |
HEAD | 请求获取URL位置资源的响应消息报告,即获得该资源的头部信息 |
POST | 请求向URL位置的资源后附新的数据 |
PUT | 请求向URL位置存储一个资源,覆盖原URL |
PATCH | 请求局部更新URL位置的资源,即改变该处资源的部分内容 |
DELETE | 请求删除URL位置存储的资源 |
2.理解PATCH和PUT的区别
假设URL位置有一组数据UserInfo,包括UserID、UserName等20个字段。
需求:用户修改了UserName,其他不变。
- 采用
PATCH
,仅向URL提交UserName的局部更新请求。 - 采用
PUT
,必须将所有20个字段一并提交到URL,未提交字段被删除。
PATCH
的最主要好处:节省网络带宽
三、Requests库的7个主要方法解析
1.requests.request()
requests.request(method,url,**kwargs)
method
:请求方式。
‘GET’、’HEAD’、’POST’、’PUT’、’PATCH’、’delete’、’OPTIONS’
**kwargs
:控制访问的参数,均为可选项。
params
:字典或字节序列,作为参数增加到url中。data
:字典、字节序列对象,重点是向服务器提交资源时使用。json
:JSON格式的数据,作为request的内容。headers
:字典,HTTP定制头。cookies
:字典或CookieJar,Request中的cookie。auth
:元祖,支持HTTP认证功能。files
:字典类型,传输文件。timeout
:设定超时时间,秒为单位。proxies
:字典类型,设定访问代理服务器,可以增加登录认证。allow_redirects
:True/False,默认为True,重定向开关。stream
:True/False,默认为True,获取内容立即下载开关。verify
:True/False,默认为True,认证SSL证书开关。cert
:本地SSL证书路径。
四、Beautiful Soup库使用
1.BeautifulSoup 基本使用
1 | from bs4 import BeautifulSoup |
2.Beautiful Soup库理解
Beautiful Soup
库,也叫做 beautifulsoup4或bs4
, 是解析、变量、维护”标签树“的功能库。只要提供的文件是标签类型,Beautiful Soup
库都可以用来解析。
因为文档和标签树是一一对应的,标签树经过Beautiful Soup
,转换为Beautiful Soup
类型。故,文档和标签树以及Beautiful Soup
是一一对应关系。
1 | from bs4 import BeautifulSoup |
Beautiful Soup
对应一个HTML/XML文档的全部内容。
3.Beautiful Soup库解析器
解析器 | 使用方法 | 条件 |
---|---|---|
bs的HTML解析器 | BeautifulSoup(mk,’html.parser’) | 安装bs4库 |
lxml的HTML解析器 | BeautifulSoup(mk,’lxml’) | pip install lxml |
lxml的XML解析器 | BeautifulSoup(mk,’xml’) | pip install lxml |
html5lib的解析器 | BeautifulSoup(mk,’htlm5lib’) | pip install html5lib |
4.Beautiful Soup类的基本元素
基本元素 | 说明 |
---|---|
Tag | 标签,最基本的信息组织单元,分别用<>和</>表面开头和结尾 |
Name | 标签的名称, … 的名字是’p’,格式: |
Attributes | 标签的属性,字典形式组织,格式: |
NavigableString | 标签内非属性字符串,<>…</>中字符串,格式: |
Comment | 标签内字符串的注释部分,一种特殊的Comment类型 |
1 | import requests |
实例一 Tag
1 | # 任何标签都可直接用soup.<标签>将其取出,当文本中存在多个相同标签时,其返回的为第一个 |
实例二 Name
1 | # 获取标签名称方法 <tag>.name |
实例三 Attributes
1 | # 获取标签的属性 <tag>.attrs |
实例四 NavigableString
1 | # 获取标签的属性 <tag>.string 用于取出标签之间的字符串 |
实例五 判断注释
1 | # 获取标签的属性 <tag>.string 用于取出标签之间的字符串 |
5.基于Beautiful Soup HTML的遍历方法
遍历方法:标签树,其为树形结构。
- 下行遍历
- 上行遍历
- 平行遍历
5.1 下行遍历
属性 | 说明 |
---|---|
.contents | 子节点的列表,将 |
.children | 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点 (返回迭代类型) |
.descendants | 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历 (同上) |
本小结实例皆以代码作为开头,不再重复写 >
代表输出
1 | import requests |
实例一 .contents
1 | soup.head.contents # 结果呈现出列表形式 |
标签树的下行遍历
- 遍历儿子节点(只遍历一层)
1 | for child in soup.body.children: |
- 遍历子孙节点(所有节点)
1 | for child in soup.body.descendants: |
5.2 标签树的上行遍历
基本代码:
1 | soup = BeautifulSoup(demo,"html.parser") |
5.3 标签树的平行遍历
属性 | 说明 |
---|---|
.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 |
.previous_sibling | 返回按照HTML文本顺序的上一个平行节点标签 |
.next_siblings | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 |
.previous_siblings | 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签 |
注意:平行遍历发生在同一个父节点下的各节点间**
实例一
1 | soup.a.next_sibling |
标签树的平行遍历基本代码
- 遍历后续节点
1 | for sibling in soup.a.next_siblings: |
- 遍历前续节点
1 | for sibling in soup.a.previous_siblings: |
6.HTML的格式化输出
6.1 prettify()方法
soup.prettify()
# 显示换行符
print(soup.prettify())
# 格式化输出,标签树形式
6.2 bs4库的编码
1 | soup = BeautifulSoup('<p>中文</p>','html.parser') |
五、信息标记的三种形式
XML
<name 属性 Attribute(包含标签 Tag)>...</name>
**JSON**
有类型的键值对 key:value
1 | # 一键多值 |
YAML
1 | name : |
1.三种信息标记形式的比较
XML
:Internet上的信息交互与传递。JSON
:移动应用云端和节点的信息通信,无注释。YAML
:各类系统的配置文件,有注释易读
2.信息提取的一般方法
- 方法一:完整解析信息的标记形式,再提取关键信息。
XML JSON YAML
需要标记解析器 例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取过程繁琐,速度慢。
- 方法二:无视标记形式,直接搜索关键信息。
搜索
对信息的文本查找函数即可
优点:提取过程简单,速度较快。
缺点:提取结果准确性与信息内容直接相关。
- 融合方法
融合方法:结合形式解析与搜索方法,提取关键信息。
XML JSON YMAL
搜索
需要标记解析器及文本查找函数
实例
提取HTML中的所有URL链接
思路:
- 搜索到所有标签
- 解析标签格式,提取href后的链接内容
3.基于bs4库的HTML内容查找方法
前期工作
1 | import requests |
<>.find_all(name,attrs,recursive,string,**kwargs)
- 返回一个列表类型,存储查找的结果。
name
:对标签名称的检索字符串。
1 | soup.find_all('a') # 返回a标签的列表,可得其中两个属性 |
attrs
:对标签属性值的检索字符串,可标注属性检索。
1 | soup.find_all('p','course') # 返回p标签中所有的course属性 |
recursive
:是否对子孙全部检索,默认True。string
:<>…</>中字符串区域的检索字符串。
1 | # 只返回检索部分 |
<tag>(...)等价于 <tag>.find_all()
soup(...)等价于soup.find_all(...)
4.扩展方法
方法 | 说明 |
---|---|
<>.find() | 搜索且只返回一个结果,字符串类型,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_parent() | 在先辈节点中返回一个结果,字符串类型,同.find()参数 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_next_sibling() | 在后续平行节点中返回一个结果,字符串类型,同.find() |
<>.find_previous_siblings() | 在前续平行节点中搜索,返回列表类型,同.find_all() |
<>.find_previous_sibling | 在前续平行节点中返回一个结果,字符串类型,同.find() |
六、正则表达式
1.正则表达式语法
1.1正则表达式由字符和操作符构成
操作符 | 说明 | 实例 |
---|---|---|
. | 表示任何单个字符 | |
[] | 字符集,对单个字符给出取值范围 | [abc]表示a,b,c;[a-z]表示a到z单个字符 |
[^] | 非字符集,对个单个字符给出排除范围 | [^abc]表示非a或b或c的单个字符 |
* | 前一个字符0次或无限次扩展 | abc*表示ab、abc、abcc、abcc等 |
+ | 前一个字符1次或无限次扩展 | abc+表示abc、abcc、abccc等 |
? | 前一个字符0次或1次扩展 | abc?表示ab、abc |
| | 左右表达式任意一个 | abc|def表示adc、def |
{m} | 扩展前一个字符m次 | ab{2}c表示abbc |
{m,n} | 扩展前一个字符m至n次(含n) | ab{1,2}c表示abc、abbc |
^ | 匹配字符串开头 | ^abc表示abc且在一个字符串的开头 |
$ | 匹配字符串结尾 | abc$表示abc且在一个字符串的结尾 |
() | 分组标记,内部只能使用|操作符 | (abc)表示abc,(abc|def)表示abc、def |
\d | 数字,等价于[0-9] | |
\w | 单词字符,等价于[A-Za-z0-9_] |
举例
正则表达式 | 对应字符串 |
---|---|
P(Y|YT|YTH|YTHO)?N | ‘PN’,’PYN’,’PYTN’,’PYTHN’,’PYTHON’ |
PYTHON+ | ‘PYTHON’,’PYTHONN’,’PYTHONNN’… |
PY[TH]ON | ‘PYTON’,’PYHON’ |
PY[^TH]?ON | ‘PYON’,’PYAON’,’PYBON’,… |
PY{:3}N | ‘PN’,’PYYN’,’PYYYN’ |
1.2经典正则表达式实例
^[A-Za-z]+$ 由26个字母组成的字符串
^[A-Za-z0-9]+$ 由26个字母和数字组成的字符串
^-?\d+$ 整数形式的字符串 - 表示负号
^[0-9]*[1-9][0-9]*$ 正整数形式的字符串
[1-9]\d{5} 中国境内邮政编码,6位
[\u4e00- \u9fa5] 匹配中文字符utf-8编码
\d{3}-\d{8}|\d{4}-\d{7} 国内电话号码,010-68913536
1.3匹配IP地址的正则表达式
IP地址字符串形式的正则表达式(IP地址分4段,每段0-255)
粗略划分:
\d+.\d+.\d+.\d+
\d{1,3}.\d{1,3}.\d{1,3}.\{1,3}
精确划分
0-99
: [1-9]?\d100-199
:1\d{2}200-249
:2[0-4]\d250-255
:25[0-5]
拼接
:(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])
2.Re库
2.1 raw string类型(原生字符串类型)
re库采用raw string类型表示正则表达式,表示为:r'text'
即:字符串原样输出,不用采用转移字符\。
2.2 Re库主要功能函数
函数 | 说明 |
---|---|
re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
re.search(pattern,string,flags=0)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象。
pattern
:正则表达式的字符串或原生字符串表示string
:待匹配字符串。flags
:正则表达式使用时的控制标记。flags
:正则表达式使用时的控制标记常用标记 说明 re.I re.IGNORECASE 忽略正则表达式的大小写,[A-Z]能够匹配小写字符 re.M
re.MULTILINE正则表达式中的^操作符能够将给定字符串的每行当做匹配开始 re.S
re.DOTALL正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符
1
2
3
4
5import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
print(match.group(0))
> 100081
re.match(pattern,string,flags=0)
1
2
3
4import re
match = re.match(r'[1-9]\d{5}','BIT 100081')
match.group(0)
> AttributeError: 'NoneType' object has no attribute 'group're.findall(pattern,string,flags=0)
1
2
3ls = re.findall(r'[1-9]\d{5}','AAA100081 BBBB100084')
ls
> ['100081', '100084']re.split(pattern,string,maxsplit,flags=0)
maxsplit
:最大分割数目,达到数目,剩余部分作为最后一个元素输出。
1
2re.split(r'[1-9]\d{5}','AAA100081 BBBB100084') # 将匹配的切割掉
> ['AAA', ' BBBB', '']re.split(pattern,string,flags=0)
1
2
3
4
5
6for m in re.finditer(r'[1-9]\d{5}','AAA100081 BBBB100084'): # 迭代输出
if m:
print(m.group(0))
>
100081
100084re.split(pattern,repl,string,count=0,flags=0)
repl
:替换匹配字符串的字符串count
:匹配的最大替换次数
2.3 Re库的另一种等价用法
rst = re.search(r'[1-9]\d{5}','BIT 100081') 函数式用法:一次性操作
等价于:
1 | # 面向对象用法:编译后的多次操作 |
regex = re.compile(pattern,flags=0)
- 将正则表达式的字符串形式编译成正则表达式对象
pattern
:正则表达式的字符串或原生字符串表示flags
:正则表达式使用时的控制标记
2.4 Match对象的属性
属性 | 说明 |
---|---|
.string | 待匹配的文本 |
.re | 匹配时使用的pattern对象(正则表达式) |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
2.5 Match对象的方法
方法 | 说明 |
---|---|
.group(0) | 获取匹配后的字符串 |
.start() | 匹配字符串在原始字符串的开始位置 |
.end() | 匹配字符串在原始字符串的结束位置 |
.span() | 返回(.start(),.end()) |
2.6 Re库的贪婪匹配和最小匹配
实例:
1 | match = re.search(r'PY.*N','PYANBNCNDN') |
Re库默认采用贪婪匹配,即输出匹配最长的子串。
最小匹配
1 | match = re.search(r'PY.*?N','PYANBNCNDN') |
最小匹配操作符
操作符 | 说明 |
---|---|
*? | 前一个字符0次或无限次扩展,最小匹配 |
+? | 前一个字符1次或无限次扩展,最小匹配 |
?? | 前一个字符0次或1次扩展,最小匹配 |
{m,n}? | 扩展前一个字符m至n次(含n),最小匹配 |