bs4简介
基本概念
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的网页信息提取库
• 安装
• pip install lxml
• pip install bs4
# 获取bs对象
bs = BeautifulSoup(html, "html.parser")
# 打印文档内容(把我们的标签更加规范的打印)
print(bs.prettify())
print(bs.title) # 获取title标签内容 <title>The Dormouse's story</title>
print(bs.title.name) # 获取title标签名称 title
print(bs.title.string) # title标签里面的文本内容 The Dormouse's story
print(bs.p) # 获取p段落
bs4的对象种类
BeautifulSoup将复杂的HTML文档转换为一个复杂的树形结构,每个节点都是一个Python对象,对象可以归四类。Tag,NavigableString,BeautifulSoup,Comment
四类主要节点
一:tag : 标签
{
name : 标签类别。如: 'b' , 'a' , 'head'...
attributes : 属性。如: <b class="boldset">有个"class"的属性,值为"boldset"。
其操作方法与字典相同,tag['class'] ,结果:'boldset'
也可以直接获取属性。tag.attrs
如果面对多值属性,返回值为List。
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]
二:NavigableString : 可导航的字符串
NavigableString类 用来包装tag中的字符串
tag.string
type(tag.string)
# <class 'bs4.element.NavigableString'>
tag.get_text()
type(tag.get_text())
<class 'str'>
三:BeautifulSoup : bs对象
BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以直接把它当作Tag对象
四:Comment : 注释
markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
print(comment)
print(type(comment))
Hey, buddy. Want to buy a used parser?
<class 'bs4.element.Comment'>
遍历
遍历文档树 遍历子节点
bs里面有三种情况,第一个是遍历,第二个是查找,第三个是修改
contents children descendants
- contents 返回的是一个所有子节点的列表
- children 返回的是一个子节点的迭代器
- descendants 返回的是一个生成器遍历子子孙孙
string strings stripped_strings
- string获取标签里面的内容
- strings 返回是一个生成器对象用过来获取多个标签内容
- stripped_strings 和strings基本一致 但是它可以把多余的空格去掉
遍历文档树 遍历父节点
parent 和 parents
- parent直接获得父节点
- parents获取所有的父节点
遍历文档树 遍历兄弟结点
- next_sibling 下一个兄弟结点
- previous_sibling 上一个兄弟结点
- next_siblings 下一个所有兄弟结点
- previous_siblings上一个所有兄弟结点
搜索树
-
字符串过滤器
-
正则表达式过滤器
我们用正则表达式里面compile方法编译一个正则表达式传给 find 或者 findall这个方法可以实现一个正则表达式的一个过滤器的搜索 -
列表过滤器
-
True过滤器(不常用)
1:name属性
string 过滤器
查找所有的b标签
soup.find_all('b')
soup.find_all(name='b')
a_tag = soup.find('a') # 找一个直接返回结果
a_tags = soup.find_all('a',id="link3")[0] # 找所有 返回列表
print(a_tags)
list 过滤器
- 查找所有的a标签以及b标签
soup.find_all(['a','b'])
正则过滤器
- 查找所有tag里面包含字母’a’的tag,包括标签
soup.find_all(re.compile('a'))
查找所有tag里面不包含’a’的tag
soup.find_all(re.compile('[^"a",]'))
True 过滤器
查找body里面所有标签
soup.find('body').find_all(True)
方法过滤器
查找xx标签,该标签前后皆是string对象
def search_a_x_b(tag):
return tag and isinstance(tag.previous_element,str) and isinstance(tag.next_element,str)
soup.find(search_a_x_b)
2. attrs属性
string 过滤器
查找所有id属性是link的tag
soup.find_all(attrs={'id':'link'})
list 过滤器
查找id属性值为link或者new_link的所有标签
soup.find_all(attrs={'id':['link','new_link']})
正则过滤器
查找id属性值中含有link的所有标签,包括link1,new_link等
soup.find_all(attrs={'id':re.compiles('link')})
True 过滤器
查找含有id属性的所有tag
soup.find_all(attrs={'id':True})
方法过滤器
查找href属性值中以.img结尾的所有tag
def search_id(attr):
return attr and attr.lower().endswith('.img')
soup.find_all(attrs={'href':search_id})
3. string/text属性
BeautifulSoup 4.6 之前的string,现在替换成了text,不过也可以使用string
string 过滤器
注意:
- 默认只返回string的值
- 可以通过previous_element属性来获得string值所在的tag
查找value是loulan的所有string
soup.find_all(string='loulan')
查找value是loulan的所有tag
[value.previous_element for value in soup.find_all(string='loulan')]
list 过滤器
查找value是’loulan’或者’nihao’的所有string
soup.find_all(string=['loulan','nihao'])
regular expression 过滤器
查找value中存在’loulan’的所有string
soup.find_all(string=re.compile('loulan'))
True 过滤器
查找在value值的所有的string
soup.find_all(string=True)
方法过滤器
查找所有value值是以loulan为结尾的string
def search_string(string):
return string and string.lower().endswith('loulan')
soup.find_all(string=search_string)
4. **kwargs属性
string
注意:因为class是保留字,所以在进行class属性的匹配时,用class_来代替
查找class属性值是loulan的所有tag
soup = Soup.find_all(class_='loulan')
list 过滤器
查找class的值是luolan或者nihao的所有tag
soup = Soup.find_all(class_=['loulan','nihao'])
正则过滤器
查找class的值包含img的所有的tag
soup = Soup.find_all(class=re.compile('loulan'))
True 过滤器
查找含有class属性的所有tag
soup = Soup.find_all(class=True)
方法过滤器
查找href值中以img结尾所有的tag
def search_img(href):
return href and href.lower().endswith('.img')
soup.find_all(href=search_img)
总结
- string过滤器主要用于完全匹配属性值
- list过滤器可以极其方便的查找多个值
- regular expression过滤器可以用于不完全匹配等其他特殊匹配
- True过滤器可以用来确定存在某些属性
- function过滤器最为强大,尽管写起来比上述几个过滤器复杂,但是可以实现任何过滤;比如两侧是string的tag,前面是strong标签后面是a标签,等等复杂过滤
参考文章
find_all() 和 find()
find_all()
- find_all()方法以列表形式返回所有的搜索到的标签数据
- find()方法返回搜索到的第一条数据
- find_all()方法参数
def find_all(self, name=None, attrs={}, recursive=True, text=None,
limit=None, **kwargs):
-
name:查找所有名字为 name 的 tag,字符串对象会被自动忽略掉。上面过滤器示例中的参数都是 name 参数。当然,其他参数中也可以使用过滤器。
-
attrs:按属性名和值查找。传入字典,key 为属性名,value 为属性值。
-
recursive:是否递归遍历所有子孙节点,默认 True。
-
text:用于搜索字符串,会找到 .string 方法与 text 参数值相符的tag,通常配合正则表达式使用。也就是说,虽然参数名是 text,但实际上搜索的是 string 属性。
-
limit:限定返回列表的最大个数。
-
kwargs:如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作 tag 的属性来搜索。这里注意,如果要按 class 属性搜索,因为 class 是 python 的保留字,需要写作 class_。
print(soup.find_all('p'))
print(type(soup.find_all('p')[0]))
for i in soup.find_all('p'):
print(i.find_all('a')) #嵌套选择
#attrs
print(soup.find_all(attrs={'href':"http://www.icourse163.org/course/BIT-268001"}))
print(soup.find_all(attrs={'id':'link1'}))
print(soup.find_all(id='link1'))
print(soup.find_all(class_='py1'))
#text查找内容
print(soup.find_all(text='This is a python demo page'))#用来做内容匹配
- find_previous_siblings() 往上搜索所有兄弟
- find_previous_sibling() 往上搜索单个兄弟
- find_all_next() 往下搜索所有元素
- find_next()往下查找单个元素
print(p_tag.find_all_next('a'))
print(p_tag.find_next('a'))
select()方法
我们也可以通过css选择器的方式来提取数据。但是需要注意的是这里面需要我们掌握css语法
CSS 选择器参考手册
修改文档树
- 修改tag的名称和属性
p_tag.name = 'w' # 修改标签的名称
p_tag['class'] = 'content' # 修改属性
- 修改string 属性赋值,就相当于用当前的内容替代了原来的内容
p_tag.string = 'you need python'
- append() 像tag中添加内容,就好像Python的列表的 .append() 方法
p_tag.append('hahaha')
- decompose() 修改删除段落,对于一些没有必要的文章段落我们可以给他删除掉
r = soup.find(class_ = 'title')
r.decompose()
print(soup)