第三章 网络爬虫之规则(BeautifulSoup篇)
●BeautifulSoup库入门
- BeautifulSoup库的安装
1.安装方法:CMD窗口->pip install beautifulsoup4
2.使用方法:from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data<>/p','html.parser')
soup = BeautifulSoup('open("D://demo.html")','html.parser')
- BeautifulSoup库的基本元素
1.BeautifulSoup库的理解:BeautifulSoup库是解析、遍历、维护“标签树”的功能库,BeautifulSoup对应一个 HTML/XML文档的全部内容(HTML文档=标签数=BeautifulSoup类)。
2.BeautifulSoup库解析器
3.BeautifulSoup类的基本元素
>>> import requests >>> r = requests.get('https://python123.io/ws/demo.html') >>> demo = r.text >>> from bs4 import BeautifulSoup >>> soup = BeautifulSoup(demo,'html.parser') #采用bs4的HTML解析器解析页面内容 >>> print(soup.prettify()) <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> >>> soup.title #title为页面在浏览器左上方显示信息位置的地方 <title>This is a python demo page</title> >>> tag = soup.a ##HTML存在多个相同tag标签时,反馈其中第一个 >>> tag <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> >>> soup.a.name ##name为字符串类型 'a' >>> soup.a.parent.name 'p' >>> soup.p.parent.name 'body' >>> tag.attrs ##标签属性实在标签中标明标签特点的相关区域,以字典形式组织 {'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'} >>> tag.attrs['class'] ['py1'] >>> tag.attrs['href'] 'http://www.icourse163.org/course/BIT-268001' >>> type(tag.attrs) <class 'dict'> >>> type(tag) <class 'bs4.element.Tag'> >>> soup.a.string 'Basic Python' >>> soup.p <p class="title"><b>The demo python introduces several python courses.</b></p> >>> soup.p.string ##string可以跨越多个标签层次 'The demo python introduces several python courses.' >>> newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>","html.parser") >>> newsoup.b.string ##分析文档时可通过类型对注释做相关判断 'This is a comment' >>> type(newsoup.b.string) <class 'bs4.element.Comment'> >>> newsoup.p.string 'This is not a comment' >>> type(newsoup.p.string) <class 'bs4.element.NavigableString'>
- 基于bs4库的HTML内容遍历方法
1.标签树的下行遍历
下行遍历结构:>>> soup.head <head><title>This is a python demo page</title></head> >>> soup.head.contents [<title>This is a python demo page</title>] >>> soup.body.contents ##儿子节点包括标签节点和字符串节点(如'\n') ['\n', <p class="title"><b>The demo python introduces several python courses.</b></p>, '\n', <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>, '\n'] >>> len(soup.body.contents) ##儿子节点数量 5 >>> soup.body.contents[1] <p class="title"><b>The demo python introduces several python courses.</b></p>
for child in soup.body.children: print(child) ##遍历儿子节点
for child in soup.body.descendants: print(child) ##遍历子孙节点
2.标签树的上行遍历
>>> soup.title.parent
<head><title>This is a python demo page</title></head>
>>> soup.html.parent ##最高级标签的父亲为自己
<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>
>>> soup.parent ##父亲为空
上行遍历结构:
>> soup = BeautifulSoup(demo,"html.parser")
>> for parent in soup.a.parents:
if parent is None:
print (parent)
else:
print(parent.name)
3.标签树的平行遍历
平行遍历条件:平行遍历发生在同一个父节点下的各节点间。
>>> soup.a.next_sibling ##标签之间的NavigableString类型也构成标签树节点,平行遍历下一个节点不一定是标签类型
' and '
>>> soup.a.next_sibling
' and '
>>> soup.a.next_sibling.next_sibling
<a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>
>>> soup.a.previous_sibling
'Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n'
>>> soup.a.previous_sibling.previous_sibling
上行遍历结构:
for sibling in soup.a.next_siblings:
print(sibling) ##遍历后续节点
for sibling in soup.a.previous_siblings
print(sibling) ##遍历前续节点
4.基于bs4库的HTML格式化和编码
bs4的prettify()方法:1)为HTML文本标签及内容增加换行符;
>>> soup.prettify()
'<html>\n <head>\n <title>\n This is a python demo page\n </title>\n </head>\n <body>\n <p class="title">\n <b>\n The demo python introduces several python courses.\n </b>\n </p>\n <p class="course">\n Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\n <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">\n Basic Python\n </a>\n and\n <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">\n Advanced Python\n </a>\n .\n </p>\n </body>\n</html>'
>>> print(soup.prettify())
<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>
2)对每个标签进行处理。
>>> print(soup.a.prettify())
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
Basic Python
</a>
●信息组织与提取方法
- 信息标记的三种形式
1.为什么要信息标记:
1)标记后的信息可形成信息组织结构,增加了信息维度
2)标记后的信息可用于通信、存储或展示
3)标记的结构与信息一样具有重要价值
4)标记后的信息更利于程序理解和运用
2.HTML(Hyper Text Makeup Language)简称超文本标记语言,是WWW(World Wide Wed)的信息组织方式,能将声音、图像、视频等超文本信息嵌入文本之中。HTML通过预定义的<>…</>标签形式组织不同类型的信息。
3.信息标记的三种形式:
1)XML(eXtensible Markup Language):
书写格式:<name>...</name>
——标签有内容
<name/>
——标签无内容
<!-- -->
——注释
2)JSON(JavsScript Object Notation):有类型的键值对key:value构成
书写格式: 多值用[,]组织——"name":["value1","value2"]
键值对嵌套用{,}——"name":{“name”:"value1","name2":"value2"}
3)YAML(YAML Ain’t Markup Language):无类型的键值对key:value构成
书写格式:缩进表达所属关系——name:
name1:value1
name2:value2
-表达并列关系——name:
-value1
-value2
|表示整块数据 #表示注释——name:| #z注释
......
- 三种信息标记形式的比较
1.XML:最早的通用信息标记语言,可扩展性好,但繁琐。应用于Internet上的信息交互与传递;
2.JSON:信息有类型,适合程序处理(),较XML简洁。应用于 移动应用云端和节点的信息通信,无注释;
3.YAML:信息无类型,文水信息比例最高,可读性好。应用于 各类系统的配置文件,有注释易读。 - 信息提取的一般方法
1.方法一:完整解析信息的标记形式,再提取关键信息。
XML、JSON 、YAML:需要标记解析器 例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取过程繁琐,速度慢。
2.方法二:无视标记形式,直接搜索关键信息。
搜索:对信息的文本查找函数即可。
优点:提取过程简洁,速度较快。
缺点:提取结果准确性与信息內容相关。
3.融合方法:结合形式解析与搜索方法,提取关键信息。
XML、JSON、YAM、搜索:需要标记解析器及文本查找函数
案例分析思路:
提取HTML中所有URL链接
思路:1)搜索到所有<‘a’>标签
2)解析<‘a‘>标签格式,提取href后的链接内容。 - 基于bs4库的HTML内容查找方法
1.<>.find_all()方法:返回一个列表类型,存储查找的结果。
使用格式: <>.find_all(name, attrs,recursive,string, **kwargs)
-name:对标签名称的检索字符串
-attrs:对标签属性值的检索字符串,可标注属性检索
-recursive:是否对子孙全部检索,默认True
-string:<>…</>中字符串区域的检索字符串
2.简写形式:< tag>(…)等价于< tag>.find all(…)
soup(…)等价于 soup. find all(…)
3.扩展方法:
●实例教程
课题:中国大学排名
功能描述;
输入;大学排名URL链接—http://www.zuihaodaxue.com/zuihaodaxuepaiming2016.html
输出;大学排名信息的屏幕输出(排名,大学名称,总分)
技术路线:requests-bs4
定向爬虫:仅对输人URL进行爬取,不扩展爬取。
程序的结构设计:
步骤1:从网络上获取大学排名网页内容getHTMLText();
步骤2:提取网页内容中信息到合适的数据结构fillUnivList();
步骤3:利用数据结构展示并输出结果printUnivList()。
程序实例::
import requests
from bs4 import BeautifulSoup
import bs4
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
def fillUnivList(ulist, html):
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr('td')
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)))
for i in range(num):
u=ulist[i]
print(tplt.format(u[0],u[1],u[2],chr(12288)))
def main():
uinfo = []
url = 'https://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 20 univs
main()
中英文混排输出问题:
中文对齐问题的原因:当中文字符宽度不够时,默认采用西文字符填充,中西文字符占用宽度不同。
问题解决:采用中文字符的空格填充chr(12288)