获取一个网页内容的函数建议采用:
import requests
def getHTMLText():
try:
r=requests.get(url,timeout=30)
r.raise_for_status() #如果状态不是200,引发异常。200成功 404失败
r.encoding='utf-8' #无论原来使用什么编码。都改成utf-8
return r.text #返回url的内容
except:
return ""
测试代码
url="http://www.baidu.com"
print(getHTMLText(url))
关于requests更多介绍:
http://docs.python-requests.org
使用requests库获取HTML页面并且将其转换为字符串后,需要进一步解析HTML页面格式,需要处理HTML和XML的函数库
beautifulsoup4库,也称Beautiful Soup库或bs4库,用于解析和处理HTML和XML,注意:它不是Beautifulsoup库。它最大的优点是能根据HTML和XML语法建立解析树,进而高效地解析其中的内容
它把每一个页面当做一个对象
使用它之前需要进行引用,可以采用from-import的方式从库中直接引用BeautifulSoup类,如下:
>>>from bs4 import BeautifulSoup
更多:http://www.crummy.com/software/BeautifulSoup/bs4
创建的BeautifulSoup对象是一个树形结构,它包含HTML页面中的每一个Tag(标签)元素,如<head>.<body>等。
具体来说,HTML中的主要结构都变成了BeautifulSoup对象的一个属性,可以直接用<a>.<b>形式获得,其中<b>的名字采用HTML中标签的名字。
>>> from bs4 import BeautifulSoup
>>> soup=BeautifulSoup(r.text)
>>> type(soup)
<class 'bs4.BeautifulSoup'>
>>> soup.head #略去<style>
<head><meta content="text/html;charset=utf-8" http-equiv="content-type"/><meta content="IE=Edge" http-equiv="X-UA-Compatible"/><meta content="always" name="referrer"/><link href="http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/><title>百度一下,你就知道</title></head>
>>> soup.head #略去<sttyle>标签输出
<head><meta content="text/html;charset=utf-8" http-equiv="content-type"/><meta content="IE=Edge" http-equiv="X-UA-Compatible"/><meta content="always" name="referrer"/><link href="http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/><title>百度一下,你就知道</title></head>
>>> title=soup.title #HTML页面标题,在<head>之中,由<title>标记
>>> title
<title>百度一下,你就知道</title>
>>> type(title)
<class 'bs4.element.Tag'>
>>> soup.body #<body>内容 每个对应的HTML Tag的属性是一个Tag类型
<body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div class="s_form"> <div class="s_form_wrapper"> <div id="lg"> <img height="129" hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270"/> </div> <form action="//www.baidu.com/s" class="fm" id="form" name="f"> <input name="bdorz_come" type="hidden" value="1"/> <input name="ie" type="hidden" value="utf-8"/> <input name="f" type="hidden" value="8"/> <input name="rsv_bp" type="hidden" value="1"/> <input name="rsv_idx" type="hidden" value="1"/> <input name="tn" type="hidden" value="baidu"/><span class="bg s_ipt_wr"><input autocomplete="off" autofocus="" class="s_ipt" id="kw" maxlength="255" name="wd" value=""/></span><span class="bg s_btn_wr"><input class="bg s_btn" id="su" type="submit" value="百度一下"/></span> </form> </div> </div> <div id="u1"> <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> <noscript> <a class="lb" href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1" name="tj_login">登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a> </div> </div> </div> <div id="ftCon"> <div id="ftConw"> <p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p> <p id="cp">©2017 Baidu <a href="http://www.baidu.com/duty/">使用百度前必读</a> <a class="cp-feedback" href="http://jianyi.baidu.com/">意见反馈</a> 京ICP证030173号 <img src="//www.baidu.com/img/gs.gif"/> </p> </div> </div> </div> </body>
>>> soup.p #页面中第一个<p>内容
<p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p>
>>>
BeautifulSoup属性与HTML的标签名称相同,远不止上述,更多请结合HTML语法理解。
每一个Tag标签在beautifulsoup4库中也是一个对象,称为Tag对象。
每个标签对象在HTML中都有类似的结构:
<a class="mnav" href="http://www.nuomi.com">糯米</a>
其中:
<>中标签的名字是name,字符串,标签的名字,比如div
其他项是attrs,字典,包含了原来页面Tag所有的属性,比如href
<>之间的内容是string,字符串,Tag所包围的文本,网页中真实的文字
contents,列表,这个Tag下所有子Tag的内容
因此,可以通过Tag对象的name、attrs、和string属性获得相应内容
>>> soup.p #页面中第一个<p>内容
<p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p>
>>> soup.a
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
>>> soup.a.name
'a'
>>> soup.a.attrs
{'href': 'http://news.baidu.com', 'name': 'tj_trnews', 'class': ['mnav']}
>>> soup.a.string
'新闻'
>>> title.name
'title'
>>> title.string
'百度一下,你就知道'
>>> soup.p.contents
[' ', <a href="http://home.baidu.com">关于百度</a>, ' ', <a href="http://ir.baidu.com">About Baidu</a>, ' ']
HTML语法可以在标签中嵌套其他标签,所以,string属性的返回值遵循如下原则。
(1)如果标签内部没有其他标签,string属性返回其中的内容
(2)如果标签内部还有其他标签,但只有一个标签,string属性返回最里面标签的内容
(3)如果标签内部有超过1层嵌套的标签,string属性返回None(空字符串)
HTML语法中同一个标签会有很多内容,例如<a>标签,百度首页一共有13处,直接调用soup.a只能返回第一个。
当需要列出标签对应的所有内容或者需要找到非第一个标签,使用BeautifulSoup的find()和find_all()方法。这两个方法会遍历整个HTML文档:
BeautifulSoup.find_all(name,attrs,recursive,string,limit)
作用:根据参数找到对应标签,返回列表类型(标签列表)
参数:
name:按照Tag标签名字检索,名字用字符串形式表示,例如div、li
attrs:按照Tag标签属性值检索,列出需要的属性名称和值,采用JSON表示
recursive:设置查找层次,只查找当前标签下一层时使用recursive=False
string:按照关键字检索string属性内容,采用string=开始
limit:返回结果的个数,默认返回全部结果
>>> a=soup.find_all('a') #查找所有的<a>
>>> len(a)
11
>>> soup.find_all('script')
[<script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script>]
>>> soup.find_all('script',{'src':'http://www/zqxiangxin.com/\jquery/jquery-1.9.4.min.js'}) #筛选,只查找src=字符和串的标签
[]
>>> import re #使用正则表达式库,可以用这个库实现字符串片段匹配
>>> soup.find_all('script',{'src':re.compile('jquery')})
[]
>>> soup.find_all(string=re.compile('百度'))
['百度一下,你就知道', '关于百度', '使用百度前必读']
>>> a
[<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="lb" href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1" name="tj_login">登录</a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>, <a href="http://home.baidu.com">关于百度</a>, <a href="http://ir.baidu.com">About Baidu</a>, <a href="http://www.baidu.com/duty/">使用百度前必读</a>, <a class="cp-feedback" href="http://jianyi.baidu.com/">意见反馈</a>]
通过片段字符串检索可以根据需要使用正则表达式re函数库,re是Python标准库。
采用re.compile('jquery')实现对片段字符串(如'jquery')的检索。
当对标签属性检索时,属性和对应的值采用JSON格式,例如:
'src':re.compile('jquery')
其中,键值对中值的部分可以是字符串或者正则表达式。
find()方法与find_all()方法的区别是,前者只返回找到的第一个结果,后者返回更多结果,所以前者返回字符串形式,后者返回列表形式。
正则表达式:
正则表达式是字符串的一种逻辑表达,一般在计算机编译器中使用。Python语言采用正则表达式辅助字符串查找。正则表达式是一种规则,只要字符串符合这个规则,就算作匹配。例如,通过re.compile()函数注册一个正则表达式'jquery',则所有包含该表达式的字符串都与它匹配。除了字符串,正则表达式还可以通过*+{}等符号扩展功能。
实例:中国大学排名爬虫
上海交通大学研发的“软科中国最好大学排名2016”:
http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html
爬虫的构建需要三个步骤:
第一、从网络上获取网页内容(requests库)
第二、分析网页内容并且提取有用数据到恰当的数据结构中(beautifulsoup4库)
第三、利用数据结构展示或进一步处理数据
为了解析网页数据,首先需要观察爬虫页面的特点,找到拟获取数据在HTML页面中的格式。打开网址,查看网页源代码。
HTML表示表格中一行地标签是<tr></tr>,在这行中,每列用<td></td>表示
整体代码如下:
import requests
from bs4 import BeautifulSoup
allUniv=[]
def getHTMLText(url):
try:
r=requests.get(url,timeout=30)
r.raise_for_status()
r.encoding='utf-8'
return r.text
except:
return ""
def fillUnivList(soup):
data=soup.find_all('tr')
for tr in data:
ltd=tr.find_all('td')
if len(ltd)==0:
continue
singleUniv=[]
for td in ltd:
singleUniv.append(td.string)
allUniv.append(singleUniv)
def printUnivList(num):
print("{:^4}{:^10}{:^5}{:^8}{:^10}".format("排名","学校名称","省市","总分","培养规模")
for i in range(num):
u=allUniv[i]
print("{:^4}{:^10}{:^5}{:^8}{:^10}".format(u[0],u[1],u[2],u[3],u[6]))
def main(num):
url='http://zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
html=getHTMLText(url)
soup=BeautifulSoup(html,"html.parser")
fillUnivList(soup)
printUnivList(num)
main(10)