爬虫之Beautifulsoup模块
一、介绍
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.目前已经开发到4.0以上了
baautiful soup常用的解析器如下:
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") |
|
|
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") |
|
|
lxml XML 解析器 |
BeautifulSoup(markup, ["lxml", "xml"]) BeautifulSoup(markup, "xml") |
|
|
html5lib | BeautifulSoup(markup, "html5lib") |
|
|
二、BeautifulSoup的使用
1、遍历文档树
遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
# 1、用法: from bs4 import BeautifulSoup soup=BeautifulSoup(html_doc,'lxml') head=soup.head # print(head) # 2、获取标签的名字: 重点 p = soup.p print(p.name) #>: p # 3、获取标签的属性 重点 p = soup.body.p # 获取body下的p标签 print(p.attrs) # 结果:{'id': 'my_p', 'class': ['title']} # 获取p标签内属性值的三种方法 p.attrs.get('class') p.get('class') p['class'] # 4、获取标签的内容 重点 ''' text: 取所选标签内下所有的文本内容 string: 若所选标签下的文本只有一个时,取到,否则为None strings: 拿到一个生成器对象,取下所选标签下的所有文本内容 stripped_strings: 是去掉空白 get_text():是用来调取内部属性text的方法。 区别:string获取的是该标签的直系内容,无法获取该标签子标签的直系内容, 而text/get_text()可以 注意:如果选标签下包含多个节点,则string输出结果是None,比如:body下有多个p节点 ''' p=soup.body.p print(p.text) print(p.string) print(p.strings) #结果:<generator object _all_strings at 0x0000026619237BF8> for line in p.stripped_strings: print(line) print(p.get_text()) # 5、嵌套选择 重点 s = soup.body.a print(s.get('id')) # 6、子节点、子孙节点 print(soup.p.contents) #取出p下的所有子节点 print(soup.p.children) #取出包含p标签下所有子节点,返回一个迭代器 print(list(soup.p.children)) # 7、父节点、祖先节点 print(soup.a.parent) #获取a标签的父节点(只有一个) print(soup.p.parent) #获取p标签的父节点 print(soup.a.parents) #返回生成器,找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲... print(list(soup.a.parents))#找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲... # 8、兄弟节点 print(soup.a.next_sibling) #下一个兄弟 print(soup.a.previous_sibling) #上一个兄弟 print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象 print(list(soup.a.previous_siblings)) #上面的兄弟们=>生成器对象
2、搜索文档树
(1)find()和find_all()
''' find_all(name , attrs , recursive , text , **kwargs) 用处:找到所有符合要求的标签 参数:name是标签名,attrs是一个字典参数,用来搜索包含特殊属性的标签,比如:data-*类型的属性 recursive:True,则会搜索当前标签的子孙节点,如果是False,则只搜索当前标签的子节点。 text: 可以是字符,列表,True,正则 注意:按类名查找的时候,关键字是class_ ''' soup.find_all('a') # soup.find(['a','p']) #找到所有a和p标签 soup.find_all('a',limit=2) #找到前两个a标签 soup.find_all('a',attrs={'data-fooo':'value'}) soup.find_all('p',attrs={'class':'title'}) soup.find_all('p',recursive=False) soup.find_all('a',text='Lacie') soup.find_all(text='Lacie') soup.find_all(class_='title') ''' find_(name , attrs , recursive , text , **kwargs) 用处:找到第一个符合要求的标签 参数:name是标签名,attrs是一个字典参数,用来搜索包含特殊属性的标签,比如:data-*类型的属性 recursive:True,则会搜索当前标签的子孙节点,如果是False,则只搜索当前标签的子节点。 text: 可以是字符,列表,True,正则 注意:按类名查找的时候,关键字是class_ ''' print(soup.find('a')) #寻找a标签 print(soup.find('a',id='link3')) #寻找id是link3的a标签 print(soup.find('a',class_='sister2')) print(soup.find('a',title='xxx')) #寻找title是xxx的a标签 ''' 区别:find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果. find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None '''
(2) 五种过滤器
''' 五种过滤器:字符串、正则表达式、列表、True、方法 ''' # 1、字符串:也就是标签名 soup.find_all('b') # 2、正则表达式 import re soup.find_all(re.compile('^b')) #找b开头的标签 # 3、列表 soup.find_all(['a','p']) # 4、True: 匹配任何值 soup.find_all(True) #查找所有标签,但是不会返回字符串节点 # 5、方法:可以是自己定义的方法 def myfunc(tag): return tag.has_attr('class') and not tag.has_attr('id') soup.find_all(myfunc())
(3)css选择器
''' css选择器:返回的是列表 ''' # 1、获取标签 print(soup.select('.element')) print(soup.select('#link3')) # 2、获取标签的属性 soup.select('#link3')[0].attrs # 3、获取标签的内容 soup.select('#link3')[0].get_text()
三国演义小说爬取案例:
# -*-coding:utf-8 -*- import requests from bs4 import BeautifulSoup import lxml headers={ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', } req=requests.get('http://www.shicimingju.com/book/sanguoyanyi.html',headers=headers) soup=BeautifulSoup(req.text,'lxml') li_list=soup.select('.book-mulu > ul > li > a') for li in li_list: url='http://www.shicimingju.com'+li['href'] title = li.string req_detail=requests.get(url,headers=headers) soup_detail=BeautifulSoup(req_detail.text,'lxml') detail_text=soup_detail.find('div',class_='chapter_content').text file_name=title+'.txt' with open(file_name,'w',encoding='utf-8') as f: f.write(detail_text) print(title+' 加载完毕')
爬肯德基餐厅信息(ajax请求,是post请求,返回的是数据)
# -*-coding:utf-8 -*- import requests import json url='http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword' headers={ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36', } # word=input(">>:") data={ 'cname': '', 'pid': '', 'keyword': '普宁', 'pageIndex': 1, 'pageSize': 10, } res=requests.post(url,data=data,headers=headers) print(res.json())
不将就