BS4
BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库,它的使用方式相对于正则来说更加的简单方便,常常能够节省我们大量的时间。
官方中文文档
https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
安装
pip install beautifulsoup4
解析器
解析器 |
使用方法 |
优势 |
劣势 |
Python标准库 |
BeautifulSoup(markup, “html.parser”) |
Python的内置标准库执行速度适中文档容错能力强 |
Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 |
BeautifulSoup(markup, “lxml”) |
速度快文档容错能力强 |
需要安装C语言库 |
lxml XML 解析器 |
BeautifulSoup(markup, [“lxml”, “xml”])``BeautifulSoup(markup, “xml”) |
速度快唯一支持XML的解析器 |
需要安装C语言库 |
html5lib |
BeautifulSoup(markup, “html5lib”) |
最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 |
速度慢不依赖外部扩展 |
由于这个解析的过程在大规模的爬取中是会影响到整个爬虫系统的速度的,所以推荐使用的是lxml,速度会快很多,而lxml需要单独安装:
1 2
| pip install lxml soup = BeautifulSoup(html_doc, 'lxml')
|
如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,所以要指定某一个解析器。
节点对象
Tag
tag就是标签的意思,tag还有许多的方法和属性。
NavigableString
BeautifulSoup
Tag和遍历文档树
tag对象可以说是BeautifulSoup中最为重要的对象,通过BeautifulSoup来提取数据基本都围绕着这个对象来进行操作。
首先,一个节点中是可以包含多个子节点和多个字符串的。例如html节点中包含着head和body节点。所以BeautifulSoup就可以将一个HTML的网页用这样一层层嵌套的节点来进行表示。
基本语法
1 2 3 4 5
| from bs4 import BeautifulSoup soup=BeautifulSoup(html_str,'lxml') type(soup)
bs4.BeautifulSoup
|
Tag 标签取出简单示例
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| from bs4 import BeautifulSoup
html_data = """ <html> <body> <div> 我们都是害虫 </div> <div id="info"> <span><span class="pl">导演</span>: <span class="attrs"><a href="/celebrity/1362276/" rel="v:directedBy">邢文雄</a></span></span><br> <span><span class="pl">编剧</span>: <span class="attrs"><a href="/celebrity/1362276/">邢文雄</a></span></span><br> <span class="actor"><span class="pl">主演</span>: <span class="attrs"><span><a href="/celebrity/1319032/" rel="v:starring">马丽</a> / </span><span><a href="/celebrity/1355058/" rel="v:starring">魏翔</a> / </span><span><a href="/celebrity/1362567/" rel="v:starring">陈明昊</a> / </span><span><a href="/celebrity/1319540/" rel="v:starring">周大勇</a> / </span><span><a href="/celebrity/1363857/" rel="v:starring">黄才伦</a> / </span><span style="display: none;"><a href="/celebrity/1350408/" rel="v:starring">艾伦</a> / </span><span style="display: none;"><a href="/celebrity/1394939/" rel="v:starring">高海宝</a> / </span><span style="display: none;"><a href="/celebrity/1386801/" rel="v:starring">韩笑</a> / </span><span style="display: none;"><a href="/celebrity/1444360/" rel="v:starring">孙贵权</a> / </span><span style="display: none;"><a href="/celebrity/1426220/" rel="v:starring">许猛</a> / </span><span style="display: none;"><a href="/celebrity/1467304/" rel="v:starring">全容杓</a> / </span><span style="display: none;"><a href="/celebrity/1467305/" rel="v:starring">卜俊男</a> / </span><span style="display: none;"><a href="/celebrity/1316008/" rel="v:starring">张志忠</a> / </span><span style="display: none;"><a href="/celebrity/1367242/" rel="v:starring">张建新</a> / </span><span style="display: none;"><a href="/celebrity/1398260/" rel="v:starring">马驰</a> / </span><span style="display: none;"><a href="/celebrity/1353283/" rel="v:starring">陶亮</a> / </span><span style="display: none;"><a href="/celebrity/1403276/" rel="v:starring">詹卢卡·佐帕</a></span><a href="javascript:;" class="more-actor" title="更多主演">更多...</a></span></span><br> <span class="pl">类型:</span> <span property="v:genre">喜剧</span><br> <span class="pl">制片国家/地区:</span> 中国大陆<br> <span class="pl">语言:</span> 汉语普通话<br> <span class="pl">上映日期:</span> <span property="v:initialReleaseDate" content="2022-02-01(中国大陆)">2022-02-01(中国大陆)</span><br> <span class="pl">片长:</span> <span property="v:runtime" content="109">109分钟</span><br> <span class="pl">又名:</span> Too Cool To Kill<br> <span class="pl">IMDb:</span> tt16254308<br>
</div> </body> </html> """
soup = BeautifulSoup(html_data, 'lxml')
print(soup.a.text, type(soup.a.text)) print(soup.a.string, type(soup.a.string)) print("===========================================================")
print(soup.a.get("href")) print("===========================================================")
body = soup.body print(list(body.children)) print("===========================================================")
print(list(body.descendants)) test = body.descendants print("===========================================================")
span = body.span print(span.next_sibling.next_sibling.next_sibling)
print(span.previous_sibling.previous_sibling)
print("===========================================================")
p_parents = span.parents print(list(p_parents))
|
1.find_all
直接通过名字和属性来进行访问,很多时候只能适用于比较简单的一些场景,所以BeautifulSoup还提供了搜索整个文档树的方法find_all()。
通过name
搜索,find_all('b')
可以直接查找出整个文档树中所有的b标签,并返回列表
通过属性搜索,我们在搜索的时候一般只有标签名是不够的,因为可能同名的标签很多,那么这时候我们就要通过标签的属性来进行搜索。这时候我们可以通过传递给attrs
一个字典参数来搜索属性。
soup.find_all(attrs={'class': 'sister'})
通过文本搜索,在find_all()方法中,还可以根据文本内容来进行搜索。soup.find_all(string="Elsie")
限制查找范围为子节点
find_all()
方法会默认的去所有的子孙节点中搜索,而如果将recursive
参数设置为False
,则可以将搜索范围限制在直接子节点中。 soup.html.find_all("title", recursive=False)
通过正则表达式来筛选查找结果在BeautifulSoup中,也是可以与re模块进行相互配合的,将re.compile
编译的对象传入find_all()
方法,即可通过正则来进行搜索。tags = soup.find_all(re.compile("^b"))
以之前的数据为例子:
1 2 3 4 5
| print(soup.find_all('a', string='邢文雄'))
print(soup.find_all('span', attrs={'class': 'pl'}))
|
2.CSS选择器
在BeautifulSoup中,同样也支持使用CSS选择器来进行搜索。使用select(),在其中传入字符串参数,就可以使用CSS选择器的语法来找到tag。
1 2
| print(soup.select('a')) print(soup.select('span > a'))
|
JSON Path
JSON Path 是一种查询语言,用于从 JSON (JavaScript Object Notation) 数据中提取和处理信息。它类似于 SQL,但专门用于与 JSON 数据交互。使用 JSON Path,可以从复杂的 JSON 结构中轻松检索特定元素或值。这在处理大型或嵌套的 JSON 数据时特别有用。
以下是 JSON Path 的一些主要用途:
- 数据提取:从 JSON 数据中选择和提取数据,例如提取特定属性的值或筛选符合特定条件的元素。
- 查询构建:创建灵活的查询来搜索和筛选 JSON 数据中的信息。
- 数据处理:简化对复杂 JSON 结构的遍历和分析,无需编写复杂的代码。
- API 交互:常用于与 RESTful API 交互时解析和处理返回的 JSON 数据。
JSON Path 通过提供一种简洁的语法来实现这些功能,使得从复杂的 JSON 结构中检索信息变得更加简单和直接。
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
| import jsonpath
dic = { "resultCode": "1", "resultMsg": "success", "reqId": "52f9f3e1-1d76-47b4-b2ae-226633b61476", "systemTime": "1681991278593", "videoInfo": { "playSta": "1", "video_image": "https://image.pearvideo.com/cont/20170714/cont-1110173-10436784.png", "srcUrl": "https://video.pearvideo.com/mp4/short/20170714/1681991278593-10632788-hd.mp4", "videos": { "hdUrl": "", "hdflvUrl": "", "sdUrl": "", "sdflvUrl": "", "srcUrl": "https://video.pearvideo.com/mp4/short/20170714/1681991278593-10632788-hd.mp4" } } }
print(jsonpath.jsonpath(dic, '$..videos.srcUrl'))
|
Xpath
简介
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
相比于BeautifulSoup,Xpath在提取数据时会更有效率。
安装
pip install lxml
语法
XPath 使用路径表达式在 XML/HTML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
下面列出了最有用的路径表达式:
谓语
谓语用来查找某个或某些特定的节点或者包含某个指定值的节点
谓语被嵌在方括号中。在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果。实例:
选取未知节点
XPath通配符可用来选取未知节点
通配符 |
描述 |
* |
匹配任何元素节点。 |
@* |
匹配任何属性节点。 |
node() |
匹配任何类型的节点。 |
选取多个路径
通过在路径表达式中使用”|”运算符,可以选取若干个路径。在下面的表格中,列出了一些路径表达式,以及这些表达式的结果:
获取节点下文本
用text()获取某个节点下的文本,用string()获取某个节点下所有的文本。
解析工具应用案例
1. 明确目标:
以豆瓣电影排行榜为案例,抓取豆瓣电影的排行榜: https://movie.douban.com/chart
需要提取的数据:
1. movie_name 2. movie_actor 3. movie_score
2. 进行伪装与请求:
进行伪装与请求:
- requests
3. 交互响应中去提取我们需要的信息:
- 正则 2. bs4 3. json() 4. xpath(可平替bs4)
4. 保存结果
- 文件
5. 代码示例
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 43 44 45 46 47 48 49
| import requests from lxml import etree
url = 'https://movie.douban.com/chart' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', } res = requests.get(url, headers=headers) with open('douban.html', 'w', encoding='utf8') as f: f.write(res.text)
with open('douban.html', 'r', encoding='utf8') as f: data = f.read()
page = etree.HTML(data)
test = page.xpath('//div[@class="pl2"]/a/text()') print(test) li = [] for i in test: movie_name = i.replace(' ', '').replace('\n', '').replace('/', '') if not movie_name: continue li.append(movie_name)
print(li)
test2 = page.xpath('//tr[@class="item"]')
movie = {} for i in yao: movie_name = i.xpath('./td/a[@class="nbg"]/@title')[0] my_key = md5(movie_name.encode()).hexdigest() movie_actor = i.xpath('./td/div/p[@class="pl"]/text()')[0] movie_score = i.xpath('./td//span[@class="rating_nums"]/text()')[0] movie.update({my_key: [{'片名':movie_name,'演员': movie_actor, '评分': movie_score}]}) print(movie)
|
6. 租客网代码示例
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
| import requests from lxml import etree import json
url = 'https://cs.zu.anjuke.com/?from=HomePage_TopBar'
res = requests.get(url)
tree = etree.HTML(res.text)
div = tree.xpath('//div[@class="zu-itemmod clearfix"]')
for i in div: title = i.xpath('./div/h3/a/b[@class="strongbox"]/text()')[0] price = i.xpath('./div//strong[@class="price"]/text()')[0] address = i.xpath('./div//address[@class="details-item tag"]/text()') """ 1.使用join 把列表转换成字符串了 2.字符串使用replace进行替换 总结: 先拼接再替换 """ address = ''.join(address).replace('\n', '').replace(' ', '').replace(' ',' ') print(address)
with open('租房信息.txt','a', encoding='utf8') as f: f.write("标题:"+ title + "\t" + "价格:" + price + "\t"+ "地址:" + address + '\n')
|