一、Beautiful Soup 库使用案例
requests 库实现了对网页内容的爬取,但是,如何从繁杂的信息中提取正真有价值的数据?
Beautiful Soup 是解析、遍历、维护“标签”树的功能库。
爬取中国最好大学排名2016 的数据:http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html
程序设计步骤:
1、获取大学排名网页内容;
2、提取网页内容中的有用信息到合适的数据结构中;
3、将爬取得大学排名打印、保存;
参考代码:
#-*- coding:utf-8 -*-
#!user/bin/python
import requests
import bs4
from bs4 import BeautifulSoup
def getHTMLText(url):
try:
r = requests.get(url,timeout = 30) # 抓取 HTML 页面内容,超时时间设置为30s
r.raise_for_status()
r.encoding = r.apparent_encoding
return(r.text)
except:
return"爬取出错"
def fillUnivList(ulist,html): # 信息提取,参数 ulist 用于存放数据的列表,html 抓取的网页内容
soup = BeautifulSoup(html, "html.parser") # html.parser 为 Beautiful Soup 库解析器
for tr in soup.find("tbody").children: # soup.find() 搜索且只返回一个结果
if isinstance(tr, bs4.element.Tag): # 判断 tr 是否是 bs4 的标签类型
tds = tr('td') # (..) 等价于.find_all(..)
ulist.append([tds[0].string, tds[1].string, tds[3].string])
def printUnivList(ulist,num): # 对抓取的数据打印
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
print(tplt.format("排名","学校名称","总分",chr(12288)))
with open("Sort.txt", 'w') as f:
f.write(("{0:^10}\t{1:{3}^10}\t{2:^10}\n").format("排名","学校名称","总分",chr(12288)))
for i in range(num):
u = ulist[i]
print(tplt.format(u[0],u[1],u[2],chr(12288)))
f.write(("{0:^10}\t{1:{3}^10}\t{2:^10}\n").format(u[0],u[1],u[2],chr(12288)))
if __name__ == '__main__':
unifo = []
print("输入需要打印的大学数量:")
num = int(input(">")) # 打印前 num 名
url = "http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html" # 中国最好大学排名
html = getHTMLText(url)
fillUnivList(unifo,html)
printUnivList(unifo,num)
下图为该网页的源代码,从该源代码中,可以看出,我们需要爬取的信息均包含在标签内。所以,要获取信息,首先需要了解HTML 、 标签树的遍历方式和HTML内容的查找方法。
二、HTML 简介
通过以下代码是 https://python123.io/ws/demo.html 的网页源代码:
查看网页源代码的python 代码:
import requests
import bs4
from bs4 import BeautifulSoup
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text # demo 为 类型
soup = BeautifulSoup(demo,"html.parser") # soup 为类型,参数html.parser为HTML解析器
print(soup.prettify()) # prettify() 方法为HTML 文本内容增加’\n’,即换行
网页源代码为:
<html>
<head>
<title>
This is a python demo page
title>
head>
<body>
<p class="title">
<b>
The demo python introduces several python courses.
b>
p>
<p class="course">
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
Basic Python
a>
and
<a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">
Advanced Python
a>
.
p>
body>
html>
从以上代码,可以看出 HTML 的一般格式为:
HTML 通过预定义的 < >……..< / > 标签形式组织不同类型的信息!
其中的标签有:< title>……< /title> < body>….< /body> < p>….< /p> < a>…< /a>
< p class = “title”> … < / p> : p 是标签名称,成对出现;class=”title” 表示属性(0个或者多个)
HTML << 标签树 << 使用 Beautiful Soup 解析
html.parser 表示 Beautiful Soup 库解析器, 一些常用的解析器有:
三、Beautiful Soup 类的基本元素(标签树的遍历方式)
每个< Tag> 都有自己的名字(字符串类型),通过< tag>.name 获取。
soup.title #获取标签title的内容 < title>This is a python demo page< /title>
tag.attrs # 获取标签的属性,每个标 签有0 个或者多个属性,属性为字典类型;
soup.prettify() #为HTML文本<>及其内容增加’\n’,是文本打印美观
< p class = “title”>….< /p>
其中,< > 内的为标签, p 为标签名称,可通过 .name 获取,class = “title” 表示属性,获取方式为:.attrs ; … 表示非属性字符串/注释, 获取方式为: .string
HTML 内容的遍历方法有:
1、标签树的下行遍历:
.contents : 子节点的列表,将< tag> 所有儿子节点存入列表
.children : 子节点的迭代类型,与 .contents 类似,用于循环遍历儿子节点
.descendants : 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历
2、标签树的上行遍历:
.parents :节点的父亲标签
.parents :节点先辈标签的迭代类型,用于循环遍历先辈节点
3、标签树的平行遍历:
.next_sibling :返回按照 HTML 文本顺序的下一个平行节点标签
.previous_sibling :返回按照 HTML 文本顺序的上一个平行节点标签
.nest_siblings :迭代类型,返回按照 HTML 文本顺序的后续所有平行节点标签
.previous_sibling :迭代类型,返回按照 HTML 文本顺序的前续所有平行节点标签
例如:遍历标签 body 的儿子节点:
for child in soup.body.children:
print(child)
平行遍历只能发生在同一个父节点下的各个子节点之间。
四、HTML内容的查找方法
1、信息标记的三种形式
HTML 是通过预定义的< >…< /> 标签形式组织不同类型的信息。在提取信息之前,需要首先了解信息的标记形式:XML、JSON、YAML。
A、XML 信息标记形式为:
< img src=”china.jpg” size = “10”>…< /img>
img 表示名称;src=”china.jpg” size = “10” 表示属性;注释的书写形式为:< !‐‐ This is a comment, very useful ‐‐>
例如:
<person>
<firstName>TianfirstName>
<lastName>SonglastName>
<address>
<streetAddr>中关村南大街5号streetAddr>
<city>北京市city>
<zipcode>100081zipcode>
address>
<prof>Computer Systemprof><prof>Securityprof>
person>
B、JSON 信息的标记形式
有类型的键值对: key:value
例如:
{
“firstName” : “Tian” ,
“lastName” : “Song” ,
“address” : {
“streetAddr” : “中关村南大街5号” ,
“city” : “北京市” ,
“zipcode” : “100081”
} ,
“prof” : [ “Computer System” , “Security” ]
}
分别对应了:一个键对应一个值;键值对嵌套;一个键对应对各值(多值用[ , ]组织)三种形式。
C、YAML 的信息标记形式
无类型键值对: key:value
例如:
firstName : Tian
lastName : Song
address :
streetAddr : 中关村南大街5号
city : 北京市
zipcode : 100081
prof :
‐Computer System
‐Security
缩进表示所属关系;-表示并列关系;# 表示注释 ; | 表示整块数据。
三种信息标记形式对比:
XML :可扩展性好,但是繁琐;用于 Internet 上的信息交互与传递。
JSON :信息有类型,适合程序处理( js ),较 XML 简洁;用于移动应用云端和节点的信息通信,无注释。
YAML :信息无类型,文本信息比例最高,可读性性好。用于各类系统的配置文件,有注释易读。
2、基于 bs4 库的HTML内容查找方法
<>.find_all(name, attrs, recursive, string, **kwargs)
∙ name :对标签名称的检索字符串
∙ attrs : 对标签属性值的检索字符串,可标注属性检索
∙ recursive: 是否对子孙全部检索,默认True
∙ string:< >…< />中字符串区域的检索字符串
例如,对网页 https://python123.io/ws/demo.html;
A、查找标签名称为“a” 的标签:
r = requests.get("https://python123.io/ws/demo.html")
r.raise_for_status()
r.encoding = r.apparent_encoding
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
print(soup.find_all("a"))
查找结果是:
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic
Pythona>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001"
id="link2">Advanced Pythona>]
B、查找查找标签名称为“a” 和“b”的标签:
soup.find_all(["a","b"])
查找结果是:
[<b>The demo python introduces several python courses.b>, <aclass="py1"href=
"http://www.icourse163.org/course/BIT-268001" id="link1">Basic Pythona>, <a
class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced
Pythona>]
C、搜索到所有< a> 标签,并且解析< a>标签格式,提取 href 后的链接格式;
r = requests.get("https://python123.io/ws/demo.html")
r.raise_for_status()
r.encoding = r.apparent_encoding
demo = r.text
soup = BeautifulSoup(demo,"html.parser")
for link in soup.find_all("a"):
print(link.get("href"))
输出结果为:
http://www.icourse163.org/course/BIT-268001
http://www.icourse163.org/course/BIT-1001870001
3、HTML内容的查找方法的扩展
——摘自:中国大学MOOC 《Python网络爬虫与信息提取》 嵩天老师课件