爬蟲MOOC 第二週 入門

首先下載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()

最後輸出效果:



箇中的表格對齊很重要,請看圖片和註釋。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章