python爬虫的页面数据解析和提取/xpath/bs4/jsonpath/正则(1)
一.数据类型及解析方式
一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值。内容一般分为两部分,非结构化的数据 和 结构化的数据。
- 非结构化数据:先有数据,再有结构,
- 结构化数据:先有结构、再有数据
- 不同类型的数据,我们需要采用不同的方式来处理。
1.非结构化的数据处理
文本、电话号码、邮箱地址
用:正则表达式
html文件
用:正则表达式 / xpath/css选择器/bs4
2.结构化的数据处理
json文件
用:jsonPath / 转化成Python类型进行操作(json类)
xml文件
用:转化成Python类型(xmltodict) / XPath / CSS选择器 / 正则表达式
下面就将常用的数据解析及提取方式进行一下学习总结,主要包括:正则,bs4,jsonpath,xpath. json数据优先选择使用jsonpath. html页面个人比较喜欢使用xpath,若使用xpath较难提取的数据可以使用bs4进行辅助, 若二者都提取不到,这时再去考虑使用正则,当然这只是个人建议,大神尽可全程高能使用正则.大佬们的牛逼人生,永远都不需要解释!!!!!!!!!!!!!!!!!
=======================邪恶的分割线==========================
二.正则表达式
正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
- 给定的字符串是否符合正则表达式的过滤逻辑(“匹配”);
- 通过正则表达式,从文本字符串中获取我们想要的特定部分(“过滤”)。
正则表达式匹配规则
Python 的 re 模块的使用
在 Python 中,我们可以使用内置的 re 模块来使用正则表达式。
有一点需要特别注意的是,正则表达式使用 对特殊字符进行转义,所以如果我们要使用原始字符串,只需加一个 r 前缀,示例: r'chuanzhiboke\t\.\tpython'
re 模块的一般使用步骤如下:
-
使用
compile()
函数将正则表达式的字符串形式编译为一个Pattern
对象 -
通过
Pattern
对象提供的一系列方法对文本进行匹配查找,获得匹配结果,一个 Match 对象。 - 最后使用
Match
对象提供的属性和方法获得信息,根据需要进行其他的操作
compile 函数
compile 函数用于编译正则表达式,生成一个 Pattern 对象,它的一般使用形式如下:
import re # 将正则表达式编译成 Pattern 对象 pattern = re.compile(r'\d+')
在上面,我们已将一个正则表达式编译成 Pattern 对象,接下来,我们就可以利用 pattern 的一系列方法对文本进行匹配查找了。
Pattern 对象的一些常用方法主要有:
- match 方法:从起始位置开始查找,一次匹配
- search 方法:从任何位置开始查找,一次匹配
- findall 方法:全部匹配,返回列表
- finditer 方法:全部匹配,返回迭代器
- split 方法:分割字符串,返回列表
- sub 方法:替换
match 方法
match 方法用于查找字符串的头部(也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果(注意贪婪与非贪婪)就返回,而不是查找所有匹配的结果。它的一般使用形式如下:
>>> import re >>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字 + 一个或者无限多个 >>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配 >>> print m None >>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配 >>> print m # 从0开始算起 None >>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配 >>> print m # 返回一个 Match 对象 <_sre.SRE_Match object at 0x10a42aac0> >>> m.group(0) # 可省略 0 '12' >>> m.start(0) # 可省略 0 起始位置 3 >>> m.end(0) # 可省略 0 结束位置 5 >>> m.span(0) # 可省略 0 区间 (3, 5)
再看看一个例子:
>>> import re >>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写 >>> m = pattern.match('Hello World Wide Web') >>> print m # 匹配成功,返回一个 Match 对象 <_sre.SRE_Match object at 0x10bea83e8> >>> m.group(0) # 返回匹配成功的整个子串 'Hello World' >>> m.span(0) # 返回匹配成功的整个子串的索引 (0, 11) >>> m.group(1) # 返回第一个分组匹配成功的子串 'Hello' >>> m.span(1) # 返回第一个分组匹配成功的子串的索引 (0, 5) >>> m.group(2) # 返回第二个分组匹配成功的子串 'World' >>> m.span(2) # 返回第二个分组匹配成功的子串 (6, 11) >>> m.groups() # 等价于 (m.group(1), m.group(2), ...) ('Hello', 'World') >>> m.group(3) # 不存在第三个分组 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: no such group
search 方法
search 方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果,当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。让我们看看例子:
>>> import re >>> pattern = re.compile('\d+') >>> m = pattern.search('one12twothree34four') # 这里如果使用 match 方法则不匹配 >>> m <_sre.SRE_Match object at 0x10cc03ac0> >>> m.group() '12' >>> m = pattern.search('one12twothree34four', 10, 30) # 指定字符串区间 >>> m <_sre.SRE_Match object at 0x10cc03b28> >>> m.group() '34' >>> m.span() (13, 15)
再来看一个例子:
# -*- coding: utf-8 -*- import re # 将正则表达式编译成 Pattern 对象 pattern = re.compile(r'\d+') # 使用 search() 查找匹配的子串,不存在匹配的子串时将返回 None # 这里使用 match() 无法成功匹配 m = pattern.search('hello 123456 789') if m: # 使用 Match 获得分组信息 print 'matching string:',m.group() # 起始位置和结束位置 print 'position:',m.span() 执行结果: matching string: 123456 position: (6, 12)
findall 方法
上面的 match 和 search 方法都是一次匹配,只要找到了一个匹配的结果就返回。然而,在大多数时候,我们需要搜索整个字符串,获得所有匹配的结果。
findall 以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。
看看例子:
import re pattern = re.compile(r'\d+') # 查找数字 result1 = pattern.findall('hello 123456 789') result2 = pattern.findall('one1two2three3four4', 0, 10) print result1 print result2 ['123456', '789'] ['1', '2']
再先看一个例子:
# re_test.py import re #re模块提供一个方法叫compile模块,提供我们输入一个匹配的规则 #然后返回一个pattern实例,我们根据这个规则去匹配字符串 pattern = re.compile(r'\d+\.\d*') #通过partten.findall()方法就能够全部匹配到我们得到的字符串 result = pattern.findall("123.141593, 'bigcat', 232312, 3.15") #findall 以 列表形式 返回全部能匹配的子串给result for item in result: print item 123.141593 3.15
finditer 方法
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。
# -*- coding: utf-8 -*- import re pattern = re.compile(r'\d+') result_iter1 = pattern.finditer('hello 123456 789') result_iter2 = pattern.finditer('one1two2three3four4', 0, 10) print type(result_iter1) print type(result_iter2) print 'result1...' for m1 in result_iter1: # m1 是 Match 对象 print 'matching string: {}, position: {}'.format(m1.group(), m1.span()) print 'result2...' for m2 in result_iter2: print 'matching string: {}, position: {}'.format(m2.group(), m2.span())
执行结果:
<type 'callable-iterator'> <type 'callable-iterator'> result1... matching string: 123456, position: (6, 12) matching string: 789, position: (13, 16) result2... matching string: 1, position: (3, 4) matching string: 2, position: (7, 8)
split 方法
split 方法按照能够匹配的子串将字符串分割后返回列表, 这个其实可算是变形的字符串方法 split() 但是使用正则的这个方法,可以指定同时按照多个规则进行切割
split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次数,不指定将全部分割。
import re p = re.compile(r'[\s\,\;]+') print p.split('a,b;; c d')
执行结果:
['a', 'b', 'c', 'd']
sub 方法
sub 方法用于替换。它的使用形式如下:
sub(repl, string[, count])
其中,repl 可以是字符串也可以是一个函数:
-
如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
-
如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
- count 用于指定最多替换次数,不指定时全部替换。
import re p = re.compile(r'(\w+) (\w+)') # \w = [A-Za-z0-9_] s = 'hello 123, hello 456' print p.sub(r'hello world', s) # 使用 'hello world' 替换 'hello 123' 和 'hello 456' print p.sub(r'\2 \1', s) # 引用分组 def func(m): return 'hi' + ' ' + m.group(2) print p.sub(func, s) print p.sub(func, s, 1) # 最多替换一次
执行结果:
hello world, hello world 123 hello, 456 hello hi 123, hi 456 hi 123, hello 456
========================邪恶的分割线==========================
三.BS4-------CSS选择器:BeautifulSoup4------完美的汤
如果只是需要简单的使用bs4进行提取数据,可以拉到本小节最后面的红色字体开始的那部分!
一.官方文档:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0
二.Beautiful Soup也是一个HTML / XML的解析器,主要的功能也是如何解析和提取HTML / XML数据。
lxml只会局部遍历,而Beautiful Soup是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
BeautifulSoup用来解析HTML比较简单,API非常人性化,支持CSS选择器,Python标准库中的HTML解析器,也支持lxml的XML解析器。
Beautiful Soup 3目前已经停止开发,推荐现在的项目使用Beautiful Soup 4.使用pip安装即可:
pip install beautifulsoup4
抓取工具 | 速度 | 使用难度 | 安装难度 |
---|---|---|---|
正则 | 最快 | 困难 | 无(内置) |
BeautifulSoup | 慢 | 最简单 | 简单 |
LXML | 快 | 简单 | 一般 |
三.简单的使用示例
from bs4 import BeautifulSoup html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ #创建 Beautiful Soup 对象 soup = BeautifulSoup(html) #打开本地 HTML 文件的方式来创建对象 #soup = BeautifulSoup(open('index.html')) #格式化输出 soup 对象的内容 print soup.prettify()
输出结果:
<html> <head> <title> The Dormouse's story </title> </head> <body> <p class="title" name="dromouse"> <b> The Dormouse's story </b> </p> <p class="story"> Once upon a time there were three little sisters; and their names were <a class="sister" href="http://example.com/elsie" id="link1"> <!-- Elsie --> </a> , <a class="sister" href="http://example.com/lacie" id="link2"> Lacie </a> and <a class="sister" href="http://example.com/tillie" id="link3"> Tillie </a> ; and they lived at the bottom of a well. </p> <p class="story"> ... </p> </body> </html>
-
如果我们在IPython2下执行,会看到这样一段警告:
-
意思是,如果我们没有显式地指定解析器,所以默认使用这个系统的最佳可用HTML解析器(“LXML”)。如果你在另一个系统中运行这段代码,或者在不同的虚拟环境中,使用不同的解析器造成行为不同。
- 但是可以我们通过
soup = BeautifulSoup(html,“lxml”)
方式指定LXML解析器。
四.bs4的四大对象种类
Beautiful Soup将复杂的HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
- 标签
- NavigableString
- BeautifulSoup
- 评论
1.标签
Tag通俗点讲就是HTML中的一个个标签,例如:
<head><title>The Dormouse's story</title></head>
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
上面的等等title
head
a
p
HTML标签加上里面包括的内容就是Tag,那么试着使用Beautiful Soup来获取标签:
from bs4 import BeautifulSoup
html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
#创建 Beautiful Soup 对象
soup = BeautifulSoup(html)
print soup.title
# <title>The Dormouse's story</title>
print soup.head
# <head><title>The Dormouse's story</title></head>
print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
print soup.p
# <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
print type(soup.p)
# <class 'bs4.element.Tag'>
我们可以利用汤加标签名轻松地获取这些标签的内容,但这些对象的类型是bs4.element.Tag
。但是注意,它查找的是在所有内容中的第一个符合要求的标签。如果要查询所有的标签,后面会进行介绍。
对于Tag,它有两个重要的属性,是名和attrs
print soup.name
# [document] #soup 对象本身比较特殊,它的 name 即为 [document]
print soup.head.name
# head #对于其他内部标签,输出的值便为标签本身的名称
print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
# 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。
print soup.p['class'] # soup.p.get('class')
# ['title'] #还可以利用get方法,传入属性的名称,二者是等价的
soup.p['class'] = "newClass"
print soup.p # 可以对这些属性和内容等等进行修改
# <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>
del soup.p['class'] # 还可以对这个属性进行删除
print soup.p
# <p name="dromouse"><b>The Dormouse's story</b></p>
2. NavigableString
既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用.string即可,例如
print soup.p.string
# The Dormouse's story
print type(soup.p.string)
# In [13]: <class 'bs4.element.NavigableString'>
3. BeautifulSoup
BeautifulSoup对象表示的是一个文档的内容。大部分时候,可以把它当作Tag对象,是一个特殊的Tag,我们可以分别获取它的类型,名称,以及属性来感受一下
print type(soup.name)
# <type 'unicode'>
print soup.name
# [document]
print soup.attrs # 文档本身的属性为空
# {}
4.评论
注释对象是一个特殊类型的NavigableString对象,其输出的内容不包括注释符号。
print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
print soup.a.string
# Elsie
print type(soup.a.string)
# <class 'bs4.element.Comment'>
a标签里的内容实际上是注释,但是如果我们利用.string来输出它的内容时,注释符号已经去掉了。
五.遍历文档树
1.直接子节点:.contents
.children
属性
。内容
tag的.content属性可以将标签的子节点以列表的方式输出
print soup.head.contents
#[<title>The Dormouse's story</title>]
输出方式为列表,我们可以用列表索引来获取它的某一个元素
print soup.head.contents[0]
#<title>The Dormouse's story</title>
。孩子
它返回的不是一个列表,不过我们可以通过遍历获取所有子节点。
我们打印输出.children看一下,可以发现它是一个list生成器对象
print soup.head.children
#<listiterator object at 0x7f71457f5710>
for child in soup.body.children:
print child
结果:
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
2.所有子孙节点:.descendants
属性
.contents和.children属性仅包含标签的直接子节点,.descendants属性可以对所有标签的子孙节点进行递归循环,和儿童类似,我们也需要遍历获取其中的内容。
for child in soup.descendants:
print child
运行结果:
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body></html>
<head><title>The Dormouse's story</title></head>
<title>The Dormouse's story</title>
The Dormouse's story
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<b>The Dormouse's story</b>
The Dormouse's story
<p class="story">Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
Elsie
,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
Lacie
and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
Tillie
;
and they lived at the bottom of a well.
<p class="story">...</p>
3.节点内容:.string
属性
如果一个标签里面没有标签了,那么.string就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么.string也会返回最里面的内容。
print soup.head.string
#The Dormouse's story
print soup.title.string
#The Dormouse's story
六.搜索文档树
1.find_all(name, attrs, recursive, text, **kwargs)
1)名称参数
name参数可以查找所有名字为name的标签,字符串对象会被自动忽略掉
A.传字符串
最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的<b>
标签:
soup.find_all('b')
# [<b>The Dormouse's story</b>]
print soup.find_all('a')
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
B.传正则表达式
如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的match()来匹配内容。下面例子中找出所有以b开头的标签,这表示<body>
和<b>
标签都应该找到
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
C.传列表
如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回。下面代码找到文档中所有<a>
标签和<b>
标签:
soup.find_all(["a", "b"])
# [<b>The Dormouse's story</b>,
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
2)关键字参数
soup.find_all(class_ = "sister")
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.find_all(id='link2')
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
3)文字参数
通过文本参数可以搜索文档中的字符串内容,与名称参数的可选值一样,text参数接受字符串,正则表达式,列表
soup.find_all(text="Elsie")
# [u'Elsie']
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(text=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]
2.find()方法
find()的用法与find_all一样,在于区别
find用于
查找第一个符合匹配查询查询结果,find_all
则用于查找所有匹配查询查询结果的列表。
3. CSS选择器(在爬虫中这是最常用的方式)
-
写CSS时,标签名不加任何修饰,类名前加英文句号 .,id名前加
#
-
在这里我们也可以利用类似的方法来筛选元素,用到的方法是
soup.select()
,返回类型是list
(1)通过标签名查找
from bs4 import BeautifulSoup html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """ #创建 Beautiful Soup 对象 soup = BeautifulSoup(html)
print soup.select('title') #[<title>The Dormouse's story</title>] print soup.select('a') # 取到了所有的a标签 #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] print soup.select('b') #[<b>The Dormouse's story</b>]
(2)通过类名查找
print soup.select('.sister') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
(3)通过id名查找
print soup.select('#link1') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
(4)组合查找
组合查找即和写类文件时,标签名与类名,id名进行的组合原理是一样的,例如查找p标签中,id等于link1的内容,二者需要用空格分开
print soup.select('p #link1') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
直接子标签查找,使用则 >
分隔
print soup.select("head > title") #[<title>The Dormouse's story</title>]
(5)属性查找
查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。
print soup.select('a[class="sister"]') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>] print soup.select('a[href="http://example.com/elsie"]') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
同样,属性仍然可以与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格
print soup.select('p a[href="http://example.com/elsie"]') #[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
(6)获取内容
soup = BeautifulSoup(html, 'lxml') print type(soup.select('title')) print soup.select('title')[0].get_text() for title in soup.select('title'): print title.get_text()
bs4基本实用的学习内容就是这些,更加详细完善的使用方法请查看官方文档
在 python爬虫的页面数据解析和提取(2) 中 再继续记录爬虫数据解析余下的内容
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗