当前位置:   article > 正文

【网络爬虫】python中的数据解析工具(re,bs4,xpath,pyquery)_re bs4 xpath

re bs4 xpath

1.基础知识

1.1 正则(re)

Regular Expression, 正则表达式, ⼀种使⽤表达式的⽅式对字符进⾏匹配的语法规则.
⽹⻚源代码本质上就是⼀个超⻓的字符串, 想从⾥⾯提取内容.⽤正则再合适不过了.
正则的优点: 速度快, 效率⾼, 准确性⾼ 正则的缺点: 新⼿上⼿难度有点⼉⾼.
不过只要掌握了正则编写的逻辑关系, 写出⼀个提取⻚⾯内容的正则其实并不复杂
正则的语法: 使⽤元字符进⾏排列组合⽤来匹配字符串
在线测试正则表达式 https://tool.oschina.net/regex/
在这里插入图片描述
元字符: 具有固定含义的特殊符号 常⽤元字符:

.      匹配除换⾏符以外的任意字符, 未来在python的re模块中是⼀个坑.
\w	   匹配字⺟或数字或下划线
\s     匹配任意的空⽩符
\d     匹配数字
\n     匹配⼀个换⾏符
\t     匹配⼀个制表符
^      匹配字符串的开始
$      匹配字符串的结尾
\W     匹配⾮字⺟或数字或下划线
\D     匹配⾮数字
\S     匹配⾮空⽩符
a|b    匹配字符a或字符b
()     匹配括号内的表达式,也表示⼀个组
[...]  匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

量词: 控制前⾯的元字符出现的次数

*      重复零次或更多次
+      重复⼀次或更多次
?      重复零次或⼀次
{n}    重复n次
{n,}   重复n次或更多次
{n,m}  重复n到m次
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

贪婪匹配和惰性匹配

.*    贪婪匹配, 尽可能多的去匹配结果
.*?   惰性匹配, 尽可能少的去匹配结果 -> 回溯
  • 1
  • 2

1.2.HTML基础语法

HTML(Hyper Text Markup Language)超⽂本标记语⾔, 是我们编写⽹⻚的最基本也是最核⼼的⼀种语⾔. 其语法规则就是⽤不同的标签对⽹⻚上的内容进⾏标记, 从⽽使⽹⻚显示出不同的展示效果.

<h1>
	我爱你
</h1>
  • 1
  • 2
  • 3

标签

上述代码的含义是在⻚⾯中显示"我爱你"三个字, 但是我爱你三个字被标记了. ⽩话就是被括起来了. 被H1这个标签括起来了. 这个时候. 浏览器在展示的时候就会让我爱你变粗变⼤. 俗称标题, 所以HTML的语法就是⽤类似这样的标签对⻚⾯内容进⾏标记. 不同的标签表现出来的效果也是不⼀样的.

h1: ⼀级标题
h2: ⼆级标题
p: 段落
font: 字体(被废弃了, 但能⽤)
body: 主体
  • 1
  • 2
  • 3
  • 4
  • 5

这⾥只是简单科普⼀下, 其实HTML标签还有很多. 就不⼀⼀列举了.

属性

<h1>
	我爱你
</h1>
<h1 align='right'>
	我爱你妹
</h1>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

有意思了. 我们发现在标签中还可以给出xxx=xxx这样的东⻄. 那么它⼜是什么呢? ⼜该如何解读呢?

⾸先, 这两个标签都是h1标签, 都是⼀级标题, 但是下⾯这个会显示在右边. 也就是说, 通过xxx=xxx这种形式对h1标签进⼀步的说明了. 那么这种语法在html中被称为标签的属性. 并且属性可以有很多个. 例如:

<body text="green" bgcolor="#eee">
	你看我的颜⾊. 贼健康
</body>
  • 1
  • 2
  • 3

总结

<标签 属性="值" 属性="值">
	被标记的内容
</标签>
  • 1
  • 2
  • 3

1.3 CSS基础语法

CSS全称层叠样式表(Cascading Style Sheets), 主要⽤来定义⻚⾯内容展示效果的⼀⻔语⾔.

HTML: ⻚⾯⻣架. 素颜 CSS: ⻚⾯效果美化. 美妆+滤镜

语法规则

  • 通过style属性来编写样式
  • 通过style标签. 然后使⽤选择器的形式来编写样式
  • 在css⽂件中编写样式, 通过link引⼊该⽂件

选择器

1. id选择器    #
2. 标签选择器  标签
3. 类选择器     .
4. 选择器分组   ,
5. 后代选择器   空格
6. ⼦选择器     >
7. 相邻选择器   +
8. 属性选择器   [属性=值]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.re模块

re模块中只需要记住这么⼏个功能

  • findall 查找所有. 返回list
lst = re.findall("m", "mai le fo len, mai ni mei!")
print(lst) # ['m', 'm', 'm']
lst = re.findall(r"\d+", "5点之前. 你要给我5000万")
print(lst) # ['5', '5000']
  • 1
  • 2
  • 3
  • 4
  • search 会进⾏匹配. 但是如果匹配到了第⼀个结果. 就会返回这个结果. 如果匹配不上search返回的则是None
ret = re.search(r'\d', '5点之前. 你要给我5000万').group()
print(ret) # 5
  • 1
  • 2
  • match 只能从字符串的开头进⾏匹配
ret = re.match('a', 'abc').group()
print(ret) # a
  • 1
  • 2
  • compile() 可以将⼀个⻓⻓的正则进⾏预加载. ⽅便后⾯的使⽤
obj = re.compile(r'\d{3}') # 将正则表达式编译成为⼀个 正则表达式对象, 规则要匹配的是3个数字
ret = obj.search('abc123eeee') # 正则表达式对象调⽤search, 参数为待匹配的字符串
print(ret.group()) # 结果: 123
  • 1
  • 2
  • 3
  • 正则中的内容如何单独提取?单独获取到正则中的具体内容可以给分组起名字
s = """
<div class='⻄游记'><span id='10010'>中国联通</span></div>
"""
obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>", re.S)
result = obj.search(s)
print(result.group()) # 结果: <span id='10010'>中国联通</span>
print(result.group("id")) # 结果: 10010 # 获取id组的内容
print(result.group("name")) # 结果: 中国联通 #获取name组的内容

# 这⾥可以看到我们可以通过使⽤分组. 来对正则匹配到的内容进⼀步的进⾏筛选.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.bs4模块安装和使用

模块安装

pip install bs4

# 如果安装速度慢可以更换国内源(阿里或者清华)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple bs4
  • 1
  • 2
  • 3
  • 4

使用

BeautifulSoup对象获取html中的内容主要通过两个⽅法来完成:
● find()
● find_all()
基本上有这两个⽅法就够⽤了. 其他的可以⾃⾏进⾏英⽂翻译就知道啥意思了.
在这里插入图片描述
不论是find还是find_all 参数⼏乎是⼀致的.
语法:
find(标签, 属性=值)
意思是在⻚⾯中查找 xxx标签, 并且标签的xxx属性必须是xxx值

例:
find(‘div’, age=18) 含义: 在⻚⾯中查找div标签, 并且属性age必须是18的这个标签.
find_all()的⽤法和find()⼏乎⼀致. find()查找1个. find_all()查找⻚⾯中所有的.

# 第一种写法
<div class="honor">

page.find("div", class="honor")
# 注意, python中class是关键字. 会报错的. 怎么办呢? 可以在class后⾯加个下划线
page.find("div", class_="honor")

#我们可以使⽤第⼆种写法来避免这类问题出现

page.find("div", attrs={"class": "honor"}) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

示例

html = """
    <ul>
        <li><a href="zhangwuji.com">张⽆忌</a></li>
        <li id="abc"><a href="zhouxingchi.com">周星驰</a></li>
        <li><a href="zhubajie.com">猪⼋戒</a></li>
        <li><a href="wuzetian.com">武则天</a></li>
    </ul>
"""
from bs4 import BeautifulSoup
page = BeautifulSoup(html, "html.parser")
lis = page.find_all("li")
for li in lis:
	print(li.find("a").get("href"))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4. xpath

XPath是⼀⻔在 XML ⽂档中查找信息的语⾔. XPath可⽤来在 XML ⽂档中对元素和属性进⾏遍历. ⽽我们熟知的HTML恰巧属于XML的⼀个⼦集. 所以完全可以⽤xpath去查找html中的内容.

基础概念

<book>
	<id>1</id>
	<name>野花遍地⾹</name>
	<price>1.23</price>
	<author>
		<nick>周⼤强</nick>
		<nick>周芷若</nick>
	</author>
</book>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上述html中,

  1. book, id, name, price…都被称为节点.
  2. Id, name, price, author被称为book的⼦节点
  3. book被称为id, name, price, author的⽗节点
  4. id, name, price,author被称为同胞节点

安装

pip install lxml 
  • 1

用法

  1. 将要解析的html内容构造出etree对象.
  2. 使⽤etree对象的xpath()⽅法配合xpath表达式来完成对数据的提取
from lxml import etree
html = """
book/*/nick
<book>
	<id>1</id>
	<name>野花遍地⾹</name>
	<price>1.23</price>
	<nick>臭⾖腐</nick>
	<author>
		<nick id="10086">周⼤强</nick>
		<nick id="10010">周芷若</nick>
		<nick class="joy">周杰伦</nick>
		<nick class="jolin">蔡依林</nick>
        <div>
			<nick>惹了</nick>
		</div>
	</author>
	<partner>
		<nick id="ppc">胖胖陈</nick>
		<nick id="ppbc">胖胖不陈</nick>
	</partner>
</book>
"""

et = etree.XML(html)
# 根据节点进⾏搜索
# result = et.xpath("/book")
# result = et.xpath("/book/id") # /在开头表示⽂档最开始, /在中间表示⼉⼦
# result = et.xpath("/book//nick") # //表示后代
result = et.xpath("/book/*/nick") # *表示通配符

print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
html = """
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8" />
	<title>Title</title>
</head>
<body>
	<ul>
		<li><a href="http://www.baidu.com">百度</a></li>
		<li><a href="http://www.google.com">⾕歌</a></li>
		<li><a href="http://www.sogou.com">搜狗</a></li>
	</ul>
	<ol>
		<li><a href="feiji">⻜机</a></li>
		<li><a href="dapao">⼤炮</a></li>
		<li><a href="huoche">⽕⻋</a></li>
	</ol>
	<div class="job">李嘉诚</div>
	<div class="common">胡辣汤</div>
</body>
</html>
"""

# xpath解析
from lxml import etree


f = open("1.html", mode="r", encoding='utf-8')
tree = etree.HTML(f.read())
result = tree.xpath("/html/body/ul/li/a/@href")
print(result)
result = tree.xpath("/html/body/ul/li")
for li in result:
	print(li.xpath("./a/@href")) # 局部解析
result = tree.xpath("//div[@class='job']/text()")  # [@class='xxx']属性选取 text()获取⽂本
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

5.pyquery

pyquery是⼀个相对新颖的数据解析⽅式. 有别于xpath和bs4. 它是使⽤css选择器作为语法规则的⼀种解析⽅式, 其⽤法⼏乎和前端的jQuery库⼀致.

安装

pip install pyquery
  • 1

使用

  • 基本使用
# 使⽤pyquery加载html代码. 此时⾃动⽣成PyQuery对象

# 导⼊pyquery
from pyquery import PyQuery as pq


html = '<li><a href="http://www.baidu.com">百度</a></li>'  # 加载HTML代码, 此时会⾃动⽣成PyQuery对象
query = pq(html)
print(query) # <li><a href="http://www.baidu.com">百度</a></li>
print(type(query)) # <class'pyquery.pyquery.PyQuery'>

# 从PyQuery对象中提取内容

# 1. 标签选择器
li = query("li")
print(li) # li标签

# 2. id选择器
a = query("#god")
print(a)

# 3. 类选择器
btn = query(".btn")
print(btn)

# 注意, 通过pyquery选择器提取的节点, 依然是pyquery对象. 所以. 就有了这种写法
# 4. 链式提取
btn = query("li")("a") # 先提取li, 然后再提取a.
print(btn)
# 但这种写法个⼈极不推荐. 看着很不舒服. 舒服的写法⼀定是这样的

# 5. 后代选择器
btn = query("li a") # 直接使⽤css选择器搞就完了.
print(btn)

# 提取⼀些重要属性试试看

# 6. 属性提取
btn = query("a")
print(btn.attr("href")) # 提取href属性. attr()的作⽤就提取属性
print(btn.text()) # 提取a标签的⽂本信息
print(btn.html()) # 提取a标签中的html信息
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 提取批量的数据
query = PyQuery(html)

# 插播⼀条根据属性提取数据
# feiji = query("a[@href='feiji']")
# print(feiji)

# 拿到所有的a标签
lis = query("li a")
a_list = lis.items() # 批量数据处理必须加上items()
for a in a_list:
	print(a.text())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • pyquery还可以对HTML结构进⾏修改
from pyquery import PyQuery as pq
html = """
	<HTML>
		<div class="aaa">哒哒哒</div>
		<div class="bbb">嘟嘟嘟</div>
	</HTML>
"""
doc = pq(html)
doc(".aaa").after("""<div class="ccc">妈呀</div>""") # 插⼊HTML代码⽚段
doc(".bbb").append("<span>我爱span</span>") # 向HTML内层标签中插⼊HTML⽚段
doc(".aaa").html("<span>我是span</span>") # 修改标签内的html代码
doc('.ccc').text("美滋滋") # 修改⽂本内容doc(".ccc").attr("cs", "测试") # 添加属性
doc(".ccc").remove_attr("cs") # 删除属性print(doc)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

文档
https://pyquery.readthedocs.io/en/latest/api.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/109146
推荐阅读
相关标签
  

闽ICP备14008679号