6.HTML内容解析-BeautifulSoup4

目录

一、安装BeautifulSoup4

二、导入 BeautifulSoup4

三、生成BeautifulSoup对象

1.解析器

2.requests与BeautifulSoup结合使用

 四、BeautifulSoup语法与使用技巧

1.查找内容

2.实例1:排除无用的信息

3.实例2:根据要求找到目标文本(根据属性值查找内容)

4.实例3:查找招聘信息中的“职位名称“”薪酬“信息。

五、HTML内容解析小结

六、练习:爬取猎聘网上的职位信息


BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库,支持你使用喜欢的解析器实现对文档的导航、查找、修改等操作。

一、安装BeautifulSoup4

pip install beautifulsoup4

二、导入 BeautifulSoup4

from bs4 import BeautifulSoup

三、生成BeautifulSoup对象

解析源代码生成BeautifulSoup对象,使用以下代码:

soup = BeautifulSoup(网页源代码,‘解析器’) 

BeautifulSoup 第一个参数应该是要被解析的文档字符串或是文件句柄,第二个参数用来标识怎样解析文档。如果第二个参数为空,那么Beautiful Soup根据当前系统安装的库自动选择解析器,解析器的优先数序: lxml,html5lib, Python标准库(html.parser)。本文中的例子将都以lxml作为解析器。

1.解析器

解析器安装:

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:

pip install lxml

另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

pip install html5lib 

解析器之间的区别:详见BeautifulSoup文档 

解析器使用方法优势劣势
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语言库
html5libBeautifulSoup(markup, "html5lib")
  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档
  • 速度慢
  • 不依赖外部扩展

2.requests与BeautifulSoup结合使用

对于网络爬虫来说,BeautifulSoup第一个参数一般来源于通过requests获得的网页源代码,也可以是一个字符串或者一个文件名称。

html = requests.get(url).content.decode('utf-8')

soup = BeautifulSoup(html,'lxml') 

 四、BeautifulSoup语法与使用技巧

1.查找内容

以下是BeautifulSoup文档中的例子

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><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>
"""

使用BeautifulSoupl浏览结构化数据 

soup.title # 获得title标签及值
# <title>The Dormouse's story</title>

soup.title.name # 获得title标签的标签名称
# u'title'

soup.title.string # 获得title标签下的字符串
# u'The Dormouse's story'

soup.title.parent.name # 获得title标签的父辈的标签名称
# u'head'

soup.p # 获得第一个p标签中的所有内容
# <p class="title"><b>The Dormouse's story</b></p> 

soup.p['class'] # 获得第一个p标签中class属性的值
# u'title'

soup.a # 获得第一个a标签中的所有内容
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

soup.find_all('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>]

soup.find(id="link3") # 获得id值为"link3"的标签的所有内容
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
print(data_soup.find_all(attrs={"data-foo": "value"})) # 使用attrs属性获得具有特殊属性名称的标签
# [<div data-foo="value">foo!</div>]

for item in soup.find_all('a'): # 获取所有的a标签,并遍历打印a标签中的href的值
    print(i.get('href'))
# http://example.com/elsie
# http://example.com/lacie
# http://example.com/tillie

for item in soup.find_all('a'): # 获取所有的a标签,并遍历打印a标签的文本值
    print(item.get_text())
# Elsie
# Lacie
# Tillie

for item in soup.find_all(class_ = 'sister'): # 获得所有class属性为sister的标签
    print(item)
# <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.a.attrs) # 获得第一个a标签中的所有属性

print([item.attrs for item in soup.find_all('a')]) # 获得所有的a标签,并遍历获得a标签中的所有属性存到列表中

2.实例1:排除无用的信息

html_doc = """
<!DOCTYPE html>
<html lang="zh-en">
<head>
    <meta charset="UTF-8"/>
    <title>网络爬虫</title>
</head>
<body>
    <div id='useful'>
        <ul>有用的信息
            <li>html</li>
            <li>css</li>
            <li>javascript</li>
        </ul>
    </div>
    <div id='useless'>
        <ul>无用的信息
            <li>python</li>
            <li>java</li>
            <li>c#</li>
        </ul>
    </div>
 
</body>
</html>
"""

代码如下:

# 方法一:
soup = BeautifulSoup(html_doc, 'lxml')
for item in soup.find_all(id='useful'):  # 使用find_all方法找到id值为“useful”的标签,find_all方法返回的是多个<class 'bs4.element.Tag'>对象的列表
    print([x.string for x in item.find_all('li')]) 

# 方法二:
item = soup.find(id="useful") # 使用find方法找到id值为“useful”的标签,find方法返回的是一个<class 'bs4.element.Tag'>对象
print([x.string for x in item.find_all('li')])

# 方法三:
for item in soup.select('div[id="useful"]'):  # 使用select找到id值为“useful”的div标签,select方法返回的是一个<class 'bs4.element.Tag'>对象
    print([x.string for x in item.find_all('li')])

# 方法四:
for item in  soup.select("#useful > ul > li"): # 使用css选择器逐层查找
    print(item.string)

3.实例2:根据要求找到目标文本(根据属性值查找内容)

html_doc = """
<html>
    <body>
        <div id="data-jobid">6575906</div>
        <div id="data-positionid">6575906</div>
        <div id="data-salary">20k-30k·16薪</div>
        <div id="data-company">耀天游戏</div>
        <div id="data-positionname">用户产品经理</div>
        <div id="data-companyid">10723</div>
        <div id="useless">无效的信息<div>
    </body>
</html>
"""

找到所有属性值以"data"开头的文本

soup = BeautifulSoup(html_doc, 'lxml')
for item in  soup.select('div[id^="data"]'):  # ^符号代表匹配以某个字符串作为开头的属性值
    print(item.get_text())

# 6575906
# 6575906
# 20k-30k·16薪
# 耀天游戏
# 用户产品经理
# 10723

找到所有属性值以“id”结尾的文本

soup = BeautifulSoup(html_doc, 'lxml')
for item in  soup.select('div[id$="id"]'):  # $符号代表匹配以某个字符串作为结尾的属性值
    print(item.get_text())

# 6575906
# 6575906
# 10723

找到所有属性值中包含"company"的文本

soup = BeautifulSoup(html_doc, 'lxml')
for item in  soup.select('div[id*="company"]'):  # *符号代表匹配包含某个字符串的属性值
    print(item.get_text())

# 耀天游戏
# 10723

***使用find_all方法和正则表达式配合也可以快捷的完成以上任务:

for item in soup.find_all(id=re.compile('^data')):  # 找到所有属性值以"data"开头的文本
    print(item.get_text())

for item in soup.find_all(id=re.compile('id$')):  # 找到所有属性值以“id”结尾的文本
    print(item.get_text())

for item in soup.find_all(id=re.compile('company')):  # 找到所有属性值中包含"company"的文本
    print(item.get_text())

4.实例3:查找招聘信息中的“职位名称“”薪酬“信息。

(数据来源:猎聘网)

html_doc = """
<html>
 <body>
  <li data-info="%7B%22job_id%22%3A35282943%2C%22job_kind%22%3A2%7D">
   <div class="sojob-item-main clearfix">
    <div class="job-info">
     <h3 title="招聘爬虫工程师">
      <a data-promid="imscid=R000000075&amp;siTag=L4PYZPMRcCAS50uKXZeG6w%7EfA9rXquZc5IkJpXC-Ycixw&amp;d_sfrom=search_fp_bar&amp;d_ckId=e3bc2e3b605ecb75d5dcdbcd2bd2be39&amp;d_curPage=0&amp;d_pageSize=40&amp;d_headId=e3bc2e3b605ecb75d5dcdbcd2bd2be39&amp;d_posi=0" href="https://www.liepin.com/job/1935282943.shtml" target="_blank">
       爬虫工程师
      </a>
     </h3>
     <p class="condition clearfix" title="15-25k·12薪_杭州_学历不限_3-5年">
      <span class="text-warning">
       15-25k·12薪
      </span>
     </p>
    </div>
   </div>
  </li>
  <li data-info="%7B%22job_id%22%3A33568633%2C%22job_kind%22%3A2%7D">
   <div class="sojob-item-main clearfix">
    <div class="job-info">
     <h3 title="招聘高级爬虫工程师">
      <a data-promid="imscid=R000000075&amp;siTag=L4PYZPMRcCAS50uKXZeG6w%7EfA9rXquZc5IkJpXC-Ycixw&amp;d_sfrom=search_fp_bar&amp;d_ckId=e3bc2e3b605ecb75d5dcdbcd2bd2be39&amp;d_curPage=0&amp;d_pageSize=40&amp;d_headId=e3bc2e3b605ecb75d5dcdbcd2bd2be39&amp;d_posi=1" href="https://www.liepin.com/job/1933568633.shtml" target="_blank">
       高级爬虫工程师
      </a>
     </h3>
     <p class="condition clearfix" title="20-40k·12薪_上海_统招本科_经验不限">
      <span class="text-warning">
       20-40k·12薪
      </span>
     </p>
    </div>
   </div>
  </li>
 </body>
</html>
"""

代码如下:

soup = BeautifulSoup(html_doc, 'lxml')
job_list = []
for item in soup.find_all('li'):  # 先抓大后抓小,分楼层抓取数据
    job_info = {}
    job_info['job_name'] = item.a.string.strip()  # 获得职位名称
    job_info['wages'] = item.span.string.strip()  # 获得薪酬信息
    job_list.append(job_info)
print(job_list)

# [{'job_name': '爬虫工程师', 'wages': '15-25k·12薪'}, {'job_name': '高级爬虫工程师', 'wages': '20-40k·12薪'}]

五、HTML内容解析小结

从网页中提取信息,是爬虫开发中最重要且是最基本的操作。正则表达式、XPath、BeautifulSoup都能用以解析网页内容,掌握并灵活运用他们从网页中获取信息,爬虫才算是入门。

正则表达式使用灵活,但构造起来较为复杂、可读性差;XPath是通过追踪解析后的标签来获得数据,使用简单,且它底层使用C语言开发,在三者之间效率最高;BeautifulSoup也是根据追踪标签来获取信息,功能强大,入门容易,但是由于是基于Python开发的,速度比XPath要满。

在实际应用中,较为推荐的是优先选择XPath,然后结合正则表达式解决一些特殊复杂情况。

六、练习:爬取猎聘网上的职位信息

猎聘网以“爬虫工程师”作为检索内容找到的职位信息

初始检索网站::https://www.liepin.com/zhaopin/?d_sfrom=search_fp_nvbar&init=1

爬取内容:职位名称、薪酬、城市、学历要求、工作经历、公司名称

变量名称:job_name,wages,city,education,work_experience,company

爬取技术:requests、BeautifulSoup4

提交资料:代码文件、数据文件csv

技术提示:1.需要装饰请求头;2.先抓大后抓小;3.薪酬、城市、学习要求和工作经历是在一个title中,需要分割;4.目前检索到的结果有10个页面,需要找到页面链接的规律。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡老师11452

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值