爬虫之Beautifulsoup模块

一、介绍

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.目前已经开发到4.0以上了

baautiful soup常用的解析器如下:

解析器使用方法优势劣势
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格式的文档
  • 速度慢
  • 不依赖外部扩展

二、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())
原文地址:https://www.cnblogs.com/nq31/p/14148692.html