一、正则表达式的使用
1.1、正则表达式
正则表达式是用来匹配字符串非常强大的工具,在其他编程语言中 同样有正则表达式的概念,Python同样不例外,利用了正则表达 式,我们想要从返回的页面内容提取出我们想要的内容就易如反掌了
1.2、规则
1.2.1、定位符
字符 | 描述 |
---|---|
^ | 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。 |
$ | 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。 |
\b | 匹配一个单词边界,即字与空格间的位置。 |
\B | 非单词边界匹配。 |
1.2.2、普通字符
字符 | 描述 |
---|---|
[ABC] | 匹配 [...] 中的所有字符,例如 [aeiou] 匹配字符串 "google runoob taobao" 中所有的 e o u a 字母 |
[^ABC] | 匹配除了 [...] 中字符的所有字符,例如 [^aeiou] 匹配字符串 "google runoob taobao" 中除了 e o u a 字母的所有字母 |
[A-Z] | [A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母 |
. | 匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r] |
[\s\S] | 匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行 |
\w | 匹配字母、数字、下划线。等价于 [A-Za-z0-9_] |
1.2.3、特殊字符
特别字符 | 描述 |
---|---|
( ) | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。 |
[ | 标记一个中括号表达式的开始。要匹配 [,请使用 \[ 。 |
? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。 |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\' 匹配 "",而 '(' 则匹配 "("。 |
{ | 标记限定符表达式的开始。要匹配 {,请使用 \{ 。 |
| | 指明两项之间的一个选择。要匹配 |,请使用 \| 。 |
1.2.4、非打印字符
字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v] |
\t | 匹配一个制表符。等价于 \x09 和 \cI |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK |
1.2.5、限定符
字符 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 |
1.2.6、数量词的贪婪模式与非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串 Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
非贪婪的则相反,总是尝试匹配尽可能少的字符
例如:正则表达式”ab”如果用于查找”abbbc”,将找到”abbb”。而如果使用非贪婪的数量词”ab?”,将找到”a”
1.2.7、正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾 |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |
1.2、常用方法
-
re.match(pattern, string, flags=0)
-
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none
-
-
re.search(pattern, string, flags=0)
-
re.search 扫描整个字符串并返回第一个成功的匹配。
-
-
re.findall(pattern,string,flags=0)
-
re.findall 查找全部
-
-
re.sub(pattern,replace,string)
-
re.sub 替换字符串
-
import re
str ='I study python3.11.8 every_day'
# 从头开始匹配,如果匹配上了返回值,如果匹配不上,返回none
print('----------------------match(规则,内容)-----------------------------')
m1 = re.match('I',str)
m2 = re.match('\w',str)
m3 = re.match('\S',str)
m4 = re.match('\D',str)
m5 = re.match('I (study)',str)
m6 = re.match('\w\s(\w*)',str)
print(m6.group(1))
# 从任意位置开始匹配,,如果匹配上了返回值,如果匹配不上,返回none
print('----------------------search(规则,内容)-----------------------------')
s1 = re.search('I',str)
s2 = re.search('study',str)
s3 = re.search('p\w+',str)
s4 = re.search('p\w+.\d+',str)
print(s4.group())
# 从任意位置开始匹配,返回所有匹配的数据,如果没有匹配内容,返回一个空列表
print('----------------------findall(规则,内容)-----------------------------')
f1 = re.findall('ddy',str)
print(f1)
# 替换原来的数据,并返回一个新的字符串,不会修改原来的字符串
print('----------------------sub(规则,替换的内容,内容)-----------------------------')
print(re.sub('p\w+','Python',str))
print(str)
二、bs4的使用
BeautifulSoup
是一个库,用于从 HTML 和 XML 文档中提取数据。它提供Pythonic 的方法来处理文档。
Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,仅仅需要说明一下原始编码方式就可以了
Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度
pip install beautifulsoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install bs4 -i https://pypi.tuna.tsinghua.edu.cn/simplepip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, “html.parser”) | 1. Python的内置标准库 2. 执行速度适中 3.文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, “lxml”) | 1. 速度快 2.文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, [“lxml”, “xml”]) BeautifulSoup(markup, “xml”) | 1. 速度快 2.唯一支持XML的解析器 3.需要安装C语言库 | |
html5lib | BeautifulSoup(markup, “html5lib”) | 1. 最好的容错性 2.以浏览器的方式解析文档 3.生成HTML5格式的文档 4.速度慢 | 不依赖外部扩展 |
三大对象种类
Tag
通俗点讲就是 HTML 中的一个个标签
NavigableString获取内容
Comment
Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦
# pip install bs4
# pip install lxml
from bs4 import BeautifulSoup
from bs4.element import Comment
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标题</title>
</head>
<body>
<div class='info' float='left'>Hello World</div>
<div class='info' float='right'>
<span>你好世界</span>
<a href='https://www.baidu.com/'>百度</a>
<strong><!--没用--></strong>
</div>
</body>
</html>
'''
bs = BeautifulSoup(html,'lxml')
print('--------------------获取标签---------------------------')
print(bs.title)
print(bs.div)
print(bs.span)
print('--------------------获取属性---------------------------')
print(bs.div.attrs)
print(bs.a.get('href'))
print(bs.a['href'])
print('--------------------获取内容---------------------------')
print(bs.div.string) # 提取可用的内容
print(bs.div.text) # 解析了标签
print('-------')
print(type(bs.strong.string))
print(type(bs.strong.text))
print('--------------------打印注释完整内容---------------------------')
if type(bs.strong.string) == Comment:
print(bs.strong.prettify())
CSS选择器
表达式 | 说明 |
---|---|
tag | 选择指定标签 |
* | 选择所有节点 |
#id | 选择id为container的节点 |
.class | 选取所有class包含container的节点 |
li a | 选取所有li下的所有a节点 |
ul + p | (兄弟)选择ul后面的第一个p元素 |
div#id > ul | (父子)选取id为id的div的第一个ul子元素 |
table ~ div | 选取与table相邻的所有div元素 |
a[title] | 选取所有有title属性的a元素 |
a[class=”title”] | 选取所有class属性为title值的a |
a[href*=”s”] | 选取所有href属性包含s的a元素 |
a[href^=”http”] | 选取所有href属性值以http开头的a元素 |
a[href$=”.png”] | 选取所有href属性值以.png结尾的a元素 |
input[type="redio"]:checked | 选取选中的hobby的元素 |
from bs4 import BeautifulSoup
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标题</title>
</head>
<body>
<div class='info' float='left'>Hello World</div>
<div class='info' float='right'>
<span>你好世界</span>
<a href='https://www.baidu.com/'>百度</a>
<strong><!--没用--></strong>
</div>
</body>
</html>
'''
bs = BeautifulSoup(html,'lxml')
print('-----------------find_all()----------------------')
print(bs.find_all('title'))
print(bs.find_all('div'))
print(bs.find_all(id='title'))
print(bs.find_all(class_='info'))
print('-------------------获取float属性为right------------------------')
print(bs.find_all(attrs={'float':'right'}))
print(bs.find_all(True))
print('-------------------组合使用------------------------')
print(bs.find_all('div',attrs={'float':'right'}))
print('-----------------css()----------------------')
print(bs.select('div'))
print(bs.select('#title'))
print(bs.select('.info'))
print(bs.select('div > span'))
print(bs.select('div.info > a'))
print('-----------------css()获取内容----------------------')
print(bs.select('div.info > a')[0].get('href'))
print(bs.select('div.info > a')[0].text)
三、pyquery的使用
pyquery
是一个类似于 jQuery 的库,允许使用 jQuery 风格的选择器来解析 HTML。
# pip install pyquery
import requests
from fake_useragent import UserAgent
from pyquery import PyQuery as pq
url = 'https://www.bqg128.com/top/'
headers = {'User-Agent':UserAgent().chrome}
resp = requests.get(url,headers=headers)
# 初始化 pyquery对象
doc = pq(resp.text)
# 提取数据
all_a = doc('div.blocks > ul > li >a')
for a in all_a:
# a 是一个element类型的数据
# 获取属性 attrib
# 获取值 text
print(a.text)
print('-------------------------------------------------')
for i in range(len(all_a)):
# a 是一个pyquery对象
# 获取属性 attr('属性')
# 获取内容 text()\html()
a = all_a.eq(i)
print(a.text())
四、xpath的使用
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上
pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple
4.1、xpath节点的关系
-
父(Parent)
-
子(Children)
-
同胞(Sibling)
-
先辈(Ancestor)
-
后代(Descendant)
4.2、xpath常用的路径表达式
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
4.3、xpath通配符
通配符 | 描述 | 举例 | 结果 |
---|---|---|---|
* | 匹配任何元素节点 | xpath('div/*') | 获取div下的所有子节点 |
@ | 匹配任何属性节点 | xpath('div[@*]') | 选取所有带属性的div节点 |
node() | 匹配任何类型的节点 |
4.4、xpath选取若干路径
表达式 | 结果 |
---|---|
xpath('//div| //table') | 获取所有的div与table节点 |
4.5、xpath谓语
表达式 | 结果 |
---|---|
xpath('/body/div[1]') | 选取body下的第一个div节点 |
xpath('/body/div[last()]') | 选取body下最后一个div节点 |
xpath('/body/div[last()-1]') | 选取body下倒数第二个节点 |
xpath('/body/div[positon()<3]') | 选取body下前两个div节点 |
xpath('/body/div[@class]') | 选取body下带有class属性的div节点 |
xpath('/body/div[@class="main"]') | 选取body下class属性为main的div节点 |
xpath('/body/div[price>35.00]') | 选取body下price元素大于35的div节点 |
4.6、xpath选择XML文件中节点
-
element(元素节点)
-
attribute(属性节点)
-
text() (文本节点)
-
concat(元素节点,元素节点)
-
comment (注释节点)
-
root (根节点)
4.7 、代码展示
# pip install lxml
import requests
from fake_useragent import UserAgent
from lxml import etree
# 找到url 地址
url ='https://www.bqg128.com/top/'
# 设置请求头
headers = {'User-Agent':UserAgent().chrome}
# 发送请求
resp = requests.get(url,headers=headers)
# 解析数据
e = etree.HTML(resp.text)
# 开始提取数据
names = e.xpath('//div[@class="blocks"]/ul/li/a/text()')
authors =[i.replace('/','').replace('\n ','') for i in e.xpath('//div[@class="blocks"]/ul/li/text()')]
# 打印结果
for n,z in zip(names,authors):
print(f'{n}==={z}')
五、json数据
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。
同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互
JSON和XML的比较可谓不相上下
Python 中自带了JSON模块,直接
import json
就可以使用官方文档:json — JSON encoder and decoder — Python 3.13.1 documentation
Json在线解析网站:JSON在线解析格式化验证 - JSON.cn
json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构
对象:对象在js中表示为{ }括起来的内容,数据结构为 { key:value, key:value, ... }的键值对的结构。
在面向对象的语言中,key为对象的属性,value为对应的属性值。
取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种
数组:数组在js中是中括号[ ]括起来的内容,数据结构为 ["Python", "javascript", "C++", ...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种
5.1、Python中的json模块
5.1.1.json.loads()
把Json格式字符串解码转换成Python对象 从json到python的类型转化
import json
strList = '[1, 2, 3, 4]'
strDict = '{"city": "北京", "name": "范爷"}'
print(json.loads(strList) )
print(json.loads(strDict))
5.1.2.json.dumps()
实现python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串
import json
dictStr = {"city": "北京", "name": "范爷"}
print(json.dumps(dictStr, ensure_ascii=False))
# 注意:json.dumps() 序列化时默认使用的ascii编码
# 添加参数 ensure_ascii=False 禁用ascii编码,按utf-8编码
5.1.3.json.dump()
将Python内置类型序列化为json对象后写入文件
import json
listStr = [{"city": "北京"}, {"name": "范爷"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)
dictStr = {"city": "北京", "name": "范爷"}
json.dump(dictStr, open("dictStr.json","w"), ensure_ascii=False)
5.1.4.json.load()
读取文件中json形式的字符串元素 转化成python类型
import json
listStr = [{"city": "北京"}, {"name": "范爷"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)
strList = json.load(open("listStr.json"))
print(strList)
5.2、jsonpath的使用
JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Python,Javascript, PHP 和 Java。
JsonPath 对于 JSON 来说,相当于 XPATH 对于 XML。
pip install jsonpath -i https://pypi.tuna.tsinghua.edu.cn/simple
官方文档:JSONPath - XPath for JSON
5.2.1、JsonPath与XPath语法对比
XPath | JSONPath | 描述 |
---|---|---|
/ | $ | 根节点 |
. | @ | 当前节点 |
/ | . or[] | 取子节点 |
.. | n/a | 取父节点,Jsonpath未支持 |
// | .. | 就是不管位置,选择所有符合条件的条件 |
* | * | 匹配所有元素节点 |
@ | n/a | 根据属性访问,Json不支持,因为Json是个Key-value递归结构,不需要。 |
[] | [] | 迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等) |
| | [,] | 支持迭代器中做多选。 |
[] | ?() | 支持过滤操作. |
n/a | () | 支持表达式计算 |
() | n/a | 分组,JsonPath不支持 |
import requests
from fake_useragent import UserAgent
from jsonpath import jsonpath
import json
url ='https://www.lagou.com/lbs/getAllCitySearchLabels.json'
headers = {'User-Agent':UserAgent().chrome}
resp = requests.get(url,headers=headers)
obj = json.loads(resp.text)
# 第一参数是obj对象 ,第二个参数是jsonpath表达式
ids = jsonpath(obj,'$..id')
names = jsonpath(resp.json(),'$..name')
for i,n in zip(ids,names):
print(f'id: {i} name: {n}')