首先下載Beautiful Soup 4,然後解壓安裝,記得安裝代碼是
python setup.py install
這裏要說明一點!!!很重要,我吃了一個多小時的虧。
我把文件命名爲 bs4.py
這時候如果要from bs4 import ... 的話,就是直接讀取文件本身,所以千萬不要亂寫腳本名字。如果把腳本名字改成 test.py 就可以了。
真的煩人。
進入演示頁面 http://python123.io/ws/demo.html
測試 bs4 安裝:
from bs4 import BeautifulSoup
到這裏如果沒問題就搞定了。
使用方法很簡單,牢記這兩行代碼就行了。
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data/p', 'html.parser') # 解析代碼
=============================================================================
HTML 代碼大概是
<html>
<body>
<p class="title"> ... </p>
</body>
</html>
這個樣的,所以 bs4 庫就是解析、遍歷、維護“標籤樹”的功能庫。
其中
<p> ... </p>
是 標籤 tag,是成對出現的。
<p class="title"> ... </p>
p是標籤的名稱,p後面那個叫屬性域,包含0個或者多個屬性域。class就是一種屬性,屬性內容是 title。
============================================================
bs4 的 HTML 解析器是 html.parser ,此外還有 lxml 和 html5lib 的解析器。
這裏主要用 HTML 解析器。
這裏假設已經獲得了網頁信息了,以下是一些命令:
# -*- coding:utf-8 -*-
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo, 'html.parser') # 解析代碼
print 'title: '
print soup.title # 打印 title 標籤
tag = soup.a # 獲取 .a 標籤,也就是鏈接標籤
print'.a tag: '
print tag
print soup.a.name #獲取 a 標籤的名字
print soup.a.parent.name # a 的父標籤的名字
print soup.a.parent.parent.name # a 的父標籤的父標籤的名字
print tag.attrs # attrs 獲得標籤的屬性(全部)
print tag.attrs['class'] # 單獨獲得某個屬性
print tag.attrs['href']
print type(tag.attrs) # 標籤屬性的類型(這裏是字典)
print type(tag) # 標籤本身的類型(就是 tag 類型)
print soup.a.string # a 標籤的 string
print soup.p # a 標籤的 string 信息 'Basic Python'
print soup.p.string # p 標籤的 string 信息
print type(soup.p.string) # p 標籤的 string 的類型
# tag 的 comment(註釋)類型
newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>", "html.parser")
print newsoup.b.string
print type(newsoup.b.string)
print newsoup.p.string
print type(newsoup.p.string) # 注意 b 和 p 標籤字符串的類型是不同的
=======================================================================
基於 bs4 庫的 html 提取方法
首先回顧 demo 的寫法:
# -*- coding:utf-8 -*-
# demo
import requests
from bs4 import BeautifulSoup
r = requests.get("http://python123.io/ws/demo.html")
demo = r.text
print demo
先說子節點的用法
# 子節點
soup = BeautifulSoup(demo, 'html.parser') # 解析代碼
print soup.head # head 標籤
print soup.head.contents # head 的子節點是 title 標籤,存在了一個列表中
print soup.body.contents # 同理,這是 body 的子節點標籤
print len(soup.body.contents) # 表示 body 的子節點的數量,這裏有五個
print soup.body.contents[1] # 這裏輸出的是第一個子節點
for child in soup.body.children: # 遍歷兒子節點
print child
for child in soup.body.descendants # 遍歷子孫節點(課上說是 children ,感覺錯了)
print child
然後是父節點
# 父節點
soup = BeautifulSoup(demo, 'html.parser') # 解析代碼
print soup.title.parent # title 標籤的父節點
print soup.html.parent # html 的父親就是他自己
print soup.parent # soup 是一個特殊標籤,他的父親是空的
for parent in soup.a.parents: # 對 a 標籤的所有先輩打印
if parent is None:
print parent # 這裏要注意
# 遍歷的時候會遍歷到 soup 本身,但是他是不存在 .name 信息的
else:
print parent.name
=============================================================================
然後平行遍歷
# 平行遍歷
soup = BeautifulSoup(demo, 'html.parser') # 解析代碼
print soup.a.next_sibling # a 標籤的下一個平行節點(不一定還是標籤,也有可能是字符串)
print soup.a.next_sibling.next_sibling # 再下一個平行節點
print soup.a.prebious_sibling # a 標籤之前的一個平行節點
print soup.a.prebious_sibling.prebious_sibling # 再前一個,也許爲空
print soup.a.parent
for sibling in soup.a.next_siblings: # 遍歷後續節點
print sibling
for sibling in soup.a.prebious_siblings: # 遍歷前續節點
print sibling
然後是輸出
# 輸出
soup = BeautifulSoup(demo, 'html.parser') # 解析代碼
print soup.prettify() # 帶換行符,這個方法就是爲文本標籤內容添加換行符
print soup.a.prettify() # 單獨打印 a 標籤
總結:
到此就是BS4基本用法,接下來講進一步用法。
==========================================================================
HTML 信息標記有三大種類 :XML, JSON, YAML
先有HTML,後有XML,它通過標籤形式來構建信息。
JSON:是有類型的鍵值對——key: value 的組合。比如 :
"name": "北京大學"
"name": ["北京大學","理學院"]
除了數字,需要雙引號。
YAML:採用無類型鍵值對——
name:北京大學
注意沒有雙引號,需要的時候可以利用縮進表達從屬,用 - 號表達並列。
XML:擴展性好,但是繁瑣
JSON:適合 JavaScript,和XML比更簡潔
YAML:文本信息比例最高,可讀性好。
================================================================
===========================================================
信息提取方法:
一、完整解析信息的標記形式,然後提取關鍵信息,比如bs4庫的標籤樹遍歷。
二、無視標記形式,直接搜索關鍵信息。
三、融合方法:結合形式解析和搜索方法,提取關鍵信息。
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo, "html.parser")
for link in soup.find_all('a'): # 查找 a 標籤
print(link.get('href')) # 得到了內容,href 是屬性。
記得之前的demo,再寫一遍:
# -*- coding:utf-8 -*-
# demo
import requests
r = requests.get("http:/python123.io/ws/demo.html")
demo = r.text
print demo
=====================================================
現在介紹 find_all :
# <>.find_all(name, attrs, recursive, string, **kwargs)
# name: 對標籤名稱的檢索字符串
# attrs: 對標籤屬性值的檢索字符串,可標註屬性檢索
# recursive: 對標籤的子孫搜索,默認爲 True
# string: <>...</> 中字符串區域的檢索字符串
print soup.find_all('a'): # 查找 a 標籤
print soup.find_all(['a','b']) # 找 a b 標籤
for tag in soup.find_all(True): # True 會顯示所有標籤信息
print(tag.name)
import re
for tag in soup.find_all(re.compile('b')) # 返回的所有以 b 開頭的信息
print tag.name
print soup.find_all('p','course') # 查找了帶有 course 屬性的 p 標籤
print soup.find_all(id = 'link1') # 屬性中 id 域爲 link1 的標籤
print soup.find_all(id = 'link') # 屬性中 id 域爲 link 的標籤
print soup.find_all(id = re.compile('link')) # 輸出以 link 開頭但是不全是 link 的信息
print soup.find_all('a', recursive = False) # 返回這裏是一個空列表,說明兒子節點上面沒有 a 標籤
print soup.find_all(string = 'Basic Python') # 精確檢索 Basic Python
print soup.find_all(string = re.compile("Python")) # 使用正則,把帶有 python 的字符串域全部檢索
以後會介紹正則庫
find_all() 函數 和 正則結合很好用。
縮寫:
<tag>(..) 等價於 <tag>.find_all(..)
soup(..) 等價於 soup.find_all(..)
=========================================================================
實戰 http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html
最好大學網的2016中國最好大學排名,這裏我們要試着使用爬蟲爬取。
功能:
輸入:大學排URL
輸出:大學排名信息的屏幕輸出(排名,大學,總分)
路線:requests / BS4
這個稱爲:定向爬蟲
先打開看看源代碼。我們要看看這個頁面的大學排名信息是動態的還是寫在源代碼中的,如果是源代碼中就有的,那麼可以爬取。
實際上打開發現是寫好了的,那麼我們可以用爬蟲爬取信息了。
<tr class="alt"><td>1</td>
<td><div align="left">清華大學</div></td>
<td>北京市</td><td>95.9</td>
然後看一看網站的robots協議。
404說明隨便爬取。
# -*- coding:utf-8 -*-
# 爬取中國最好大學數據
import requests
from bs4 import BeautifulSoup
import bs4
def getHTMLText(url): # 從網絡上獲取大學排名網頁內容
try:
r = requests.get(url, timeout = 30) # 限定時間 30 秒
r.raise_for_status() # 有問題就產生異常
r.encoding = r.apparent_encoding # 編碼
return r.text
except:
return "" # 否則返回空字符串
def fillUnivList(ulist, html ): # 提取網頁內容中信息到合適的數據結構
# 注意這裏的 "tbody"/"td"/"tr" 都是根據網頁源代碼來的
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children: # 遍歷、查找在 tbody 中子標籤中的 tr 標籤,tr 包含大學信息
if isinstance(tr, bs4.element.Tag): # 檢測 tr 標籤類型,如果不是 bs4 庫定義的 tag 類型,則過濾掉
tds = tr('td') # 把所有的 td 標籤存爲列表 tds
ulist.append([tds[0].string, tds[1].string, tds[2].string]) # 把需要的 td 標籤加入到 ulist
def printUnivList(ulist, num ): # 利用數據結構展示並輸出結果
tplt = "{0:^10}\t{1:{3}^10}\t{2:^10}"
# 注意 ":" 是引導符號,"3"是填充的字符,"^" 是居中對齊符號,"10"是寬度,最前面"0"、"1"、"2"是順序
# chr 12288是中文空格變量
print (tplt.format("排名", "學校名稱", "總分",chr(12288))) # format 方法格式化輸出
for i in range(num):
u = ulist[i] # 所有信息保存在 ulist 中
print (tplt.format(u[0], u[1], u[2],chr(12288))) # 格式化輸出
def main(): # 主函數
uinfo = [] # 大學信息放在 uinfo 列表
url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2016.html'
html = getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 打印 20 所大學信息
main()
最後輸出效果:
箇中的表格對齊很重要,請看圖片和註釋。