python数据采集2-HTML解析

python数据采集2-HTML解析

BeautifulSoup

CSS 可以让 HTML 元素呈现出差异化,
使那些具有完全相同修饰的元素呈现出不同的样式。比如,有一些标签看起来是这样:

<span class="green"></span>

<span class="red"></span>

网络爬虫可以通过 class 属性的值,轻松地区分出两种不同的标签。例如,它们可以用
BeautifulSoup 抓取网页上所有的红色文字,而绿色文字一个都不抓。因为 CSS 通过属性准
确地呈现网站的样式,所以你大可放心,大多数新式网站上的 class 和 id 属性资源都非常
丰富。

下面让我们创建一个网络爬虫来抓取 http://www.baidu.com
这个网页。

<div id="u1"><a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a><a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a><a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a><a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a><a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a><a href="http://xueshu.baidu.com" name="tj_trxueshu" class="mnav">学术</a><a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F&amp;sms=5" name="tj_login" class="lb" onclick="return false;">登录</a><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产品</a><div class="bdnuarrow bdbriarrow" style="display: none;"></div></div>
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:20:19 2018

@author: 
"""

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")
nameList = bsObj.findAll("a", {"class":"mnav"})
for name in nameList:
   print(name.get_text())

输出结果

新闻
hao123
地图
视频
贴吧
学术

之前,我们调用 bsObj.tagName只能获取页面中的第一个指定的标签。现在,我们
调用 bsObj.findAll(tagName, tagAttributes)可以获取页面中所有指定的标签,不再只是
第一个了。

获取namelist列表之后,程序遍历列表中所有的name,然后打印name.get_text(),就可以把标
签中的内容分开显示了。

get_text()会把你正在处理的 HTML 文档中所有的标签都清除,然后返回
一个只包含文字的字符串。假如你正在处理一个包含许多超链接、段落和标
签的大段源代码,那么 .get_text() 会把这些超链接、段落和标签都清除掉,
只剩下一串不带标签的文字。

BeautifulSoup对象查找你想要的信息,比直接在 HTML 文本里查找信
息要简单得多。通常在你准备打印、存储和操作数据时,应该最后才使
用 .get_text() 。一般情况下,你应该尽可能地保留 HTML 文档的标签结构。

BeautifulSoup的 find() 和 findAll()

BeautifulSoup 里的 find() 和 findAll() 可能是你最常用的两个函数。借助它们,你可以通
过标签的不同属性轻松地过滤 HTML 页面,查找需要的标签组或单个标签。

findAll(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)

注解

tag标签参数,前面已经介绍过——你可以传一个标签的名称或多个标签名称组成的 Python
列表做标签参数。例如,下面的代码将返回一个包含 HTML 文档中所有标题标签的列表:

.findAll({"h1","h2","h3","h4","h5","h6"})

attributes属性参数 ,是用一个 Python 字典封装一个标签的若干属性和对应的属性值,

如,下面这个函数会返回 HTML 文档里红色与绿色两种颜色的 span 标签:

.findAll("span", {"class":{"green", "red"}})

recursive递归参数,是一个布尔变量,如果 recursive设置为FalsefindAll就只查找文档的一级标签。 findAll
默认是支持递归查找的( recursive默认值是 True

text文本参数,有点不同,它是用标签的文本内容去匹配,而不是用标签的属性。假如我们
想查找前面网页中包含“the prince”内容的标签数量,我们可以把之前的 findAll 方法换
成下面的代码:

nameList = bsObj.findAll(text="学术")
print(len(nameList))

输出结果为“1”。

limit范围限制参数,显然只用于 findAll 方法。 find 其实等价于 findAll 的 limit 等于
1 时的情形。

keyword关键词参数,可以让你选择那些具有指定属性的标签。例如:

allText = bsObj.findAll(id="text")
print(allText[0].get_text())

注意

下面两行代码是完全一样的:

bsObj.findAll(id="text")
bsObj.findAll("", {"id":"text"})

用 keyword 偶尔会出现问题,尤其是在用 class 属性查找标签的时候,
因为 class 是 Python 中受保护的关键字。

bsObj.findAll(class=“green”)

正确的姿势

bsObj.findAll(class_=“green”)

bsObj.findAll("", {“class”:“green”})

导航树

# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018

@author: 
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")
print(bsObj.html.body.a)

输出

<a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})"><img alt="到百度首页" src="//www.baidu.com/img/baidu_jgylogo3.gif" title="到百度首页"/></a>

处理子标签

百度部分代码

<html><body>
<div id="u1">
    <a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
    <a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
    <a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a>
    <a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a>
    <a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a>
    <a href="http://xueshu.baidu.com" name="tj_trxueshu" class="mnav">学术</a>
    <a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F&amp;sms=5" name="tj_login" class="lb" onclick="return false;">登录</a>
    <a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产品</a>
    <div class="bdnuarrow bdbriarrow" style="display: none;"></div>
</div>
</body></html>
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018

@author: 
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html,"lxml")
for child in bsObj.find("div",{"id":"u1"}).children:
    print(child)

输出结果

<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧</a>
<a class="mnav" href="http://xueshu.baidu.com" name="tj_trxueshu">学术</a>
<a class="lb" href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F&amp;sms=5" name="tj_login" onclick="return false;">登录</a>
<a class="pf" href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon">设置</a>
<a class="bri" href="http://www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>

处理兄弟标签

BeautifulSoup 的 next_siblings()

# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018

@author: 
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")

for sibling in bsObj.find("div",{"id":"u1"}).a.next_siblings:
    print(sibling) 
    
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧</a>
<a class="mnav" href="http://xueshu.baidu.com" name="tj_trxueshu">学术</a>
<a class="lb" href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F&amp;sms=5" name="tj_login" onclick="return false;">登录</a>
<a class="pf" href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon">设置</a>
<a class="bri" href="http://www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>

next_siblings一样,如果你很容易找到一组兄弟标签中的最后一个标签,那么
previous_siblings函数也会很有用。

处理父元素

同理如上
关键字parent

posted @ 2018-10-01 23:03  孙中明  阅读(317)  评论(0编辑  收藏  举报