Python網路資料採集(爬蟲)

努力一點點堅持一點點發表於2017-10-15

原書連結:https://pan.baidu.com/s/1eTSi3FO 密碼:9uy1

 

寫程式碼之前擬個大綱或畫個流程圖是很好的程式設計習慣,這麼做不僅可以為你後期處理節省 很多時間,更重要的是可以防止自己在爬蟲變得越來越複雜時亂了分寸。(自己當產品經理)

新增處理異常會讓程式碼更好體驗在寫爬蟲的時候,思考程式碼的總體格局,讓程式碼既可以捕捉異常又容易閱讀,這是很重要 的。如果你還希望能夠很大程度地重用程式碼,那麼擁有像 getSiteHTML 和 getTitle 這樣的 通用函式(具有周密的異常處理功能)會讓快速穩定地網路資料採集變得簡單易行。

豆瓣目錄   

如果你想入門爬蟲,推薦這本書,此書使用的是Py3.

第一,二章直接推薦大家使用BeautifulSoup來解析網頁,個人覺得最好用的還是lxml,但是本書並沒有講到。BS的使用分為三個步驟,建立,搜尋,訪問。直接引用標籤只會返回第一個匹配的element,你如果想要返回多個那麼就要使用find_all,如果限制訪問個數擇則有一個limit屬性,如果訪問標籤不存在則會返回None,但是如果繼續訪問這個不存在標籤的屬性,則會返回Error,所以使用要注意。其他的使用還有很多,例如Navigating Trees,BS最最強大的在於它支援ReEx,還有很多小的細節,訪問節點的三種方式,匿名函式,最後也推薦了lxml。個人提示,當你的電腦裝了lxml之後,在使用Bs建立物件的時候,加上html的解析器屬性--html.parser
第三章,爬蟲的基礎,算是前面講解的實戰。
第四章,使用API爬取資訊,可以省略大部分,後面關於JSON的解析有必要注意一下,loads,jumps直接對於Json格式和字典的轉換。
第五章,儲存資料,介紹了CSV(comma-separated values),以及MySQL,MySQL的使用可以專門去學習,而且很重要。Py2中是用MySQLdb庫來運算元據庫,在Py3中則換用PyMySQL,最後則是講解了使用smtplib來傳送Email,因人而異的功能。
第六章,文字的操作,手先講解了編碼的處理,decode > unicode > encode,utf8只是unicode的編碼實現方式。首先是如何處理CSV檔案(CSV),然後PDF(pdfminer)及docx(zipfile)
第七章,高階爬蟲的技巧,也是我看本書的最終目的。本章著重講解資料的清洗,使用正則,或者repalce一下,其實python的numpy或者pandas在這方面已經很優秀。同時本書介紹了專門的軟體按OpenRefine.
第八章,馬爾可夫模型生成偽隨機文字,還介紹了NLTK工具包,這個英文支援良好,中文不瞭解。
第九章,模擬登入,使用強大的requests。保持登入使用session來訪問,最後稍微講解了Auth。
第十章,Js解析,使用selenium和PhantomJS來解析網頁,通過呼叫API來實現一些操作,最後處理了客戶端Js重定向問題,伺服器端不用擔心,因為Python的內建庫檔案自動執行
第十一章,影像識別,反爬蟲機制的發展是不斷上升的過程。在CAPTCHAs可以使用PIL簡單識別,或者使用Tesseract來模擬訓練,影像識別或者說OCR本身就是很大的方向,可忽略
第十二章,避免爬蟲陷阱,介紹一些坑爹的頁面反爬蟲機制及處理方式
第十三章,測試技巧,使用unittest或selenium測試
第十四章,IP限制使用Tor,但是國內被牆製作瞭解,及使用Google或者AWS的雲服務
下面需要看一下演算法或者深入機器學習的書籍,資料的獲取和處理,我想作為一個數學系的學生,重點是如何Learning,如何去特徵提取,Python的程式設計只是加分項,我也只把Python作為唯一的程式設計工具,原始碼需要學習。

第一部分 建立爬蟲 

 採集資訊用的程式一般被稱為網路爬蟲(Web crawler)、網路鏟(Web scraper,可類比考古用的洛陽鏟)、網路蜘蛛(Webspider),其行為一般是先“爬”到對應的網頁上,再把需要的資訊“鏟”下來。網路資料採集程式也像是一隻辛勤採蜜的小蜜蜂,它飛到花(目標網頁)上,採集花粉(需要的資訊),經過處理(資料清洗、儲存)變成蜂蜜(可用的資料)。

思考“網路爬蟲”時通常的想法:(就是自己寫api)
 • 通過網站域名獲取HTML 資料
 • 根據目標資訊解析資料
 • 儲存目標資訊
 • 如果有必要,移動到另一個網頁重複這個過程

用虛擬環境儲存庫檔案
    如果同時負責多個 Python 專案,或者想要輕鬆打包某個專案及其關聯的庫檔案,再 或者你擔心已安裝的庫之間可能有衝突,那麼你可以安裝一個 Python 虛擬環境來分而 治之。(大事化小)

    將專案關聯的所有庫單獨放在一個虛擬環境裡,還可以輕鬆打包整個環境發生給其他 人。只要他們的 Python 版本和你的相同,你打包的程式碼就可以直接通過虛擬環境運 行,不需要再安裝任何庫。

urlopen 用來開啟並讀取一個從網路獲取的遠端物件。因為它是一個非常通用的庫(它可以輕鬆讀取 HTML 檔案、影像檔案,或其他任何檔案流)。

異常檢測:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import sys

def getTitle(url):
    try:
        html = urlopen(url)
    except HTTPError as e:
        print(e)
        return None
    try:
        bsObj = BeautifulSoup(html.read())
        title = bsObj.body.h1
    except AttributeError as e:
        return None
    return title

title = getTitle("http://www.pythonscraping.com/exercises/exercise1.html")
if title == None:
    print("Title could not be found")
else:
    print(title)

    這個例子中,我們建立了一個getTitle 函式,可以返回網頁的標題,如果獲取網頁的時候遇到問題就返回一個None 物件。在getTitle 函式裡面,我們像前面那樣檢查了HTTPError,然後把兩行BeautifulSoup 程式碼封裝在一個try 語句裡面。這兩行中的任何一行有問題,AttributeError 都可能被丟擲(如果伺服器不存在,html 就是一個None 物件,html.read() 就會丟擲AttributeError)。其實,我們可以在try 語句裡面放任意多行程式碼,或者放一個在任意位置都可以丟擲AttributeError 的函式。

 

複雜HTML解析

在面對埋藏很深或格式不友好的資料時,千萬不要不經思考就寫程式碼,一定要三思 而後行。(手機端、、、)
 

BeautifulSoup強大過濾能力  假如你正在處理一個包含許多超連結、段落和標籤的大段原始碼,那麼.get_text() 會把這些超連結、段落和標籤都清除掉,只剩下一串不帶標籤的文字。通常在你準備列印、儲存和運算元據時,應該最後才使用.get_text()。一般情況下,你應該儘可能地保留HTML 文件的標籤結構。陣列轉為物件

.findAll({"h1","h2","h3","h4","h5","h6"})

.findAll("span", {"class":{"green", "red"}})

nameList = bsObj.findAll("span", {"class":"green"})
           
下面兩行程式碼是完全一樣的:
bsObj.findAll(id="text") 
bsObj.findAll("", {"id":"text"})

返回的列表

選擇器強大,類似css選擇器,兄弟,後代(導航樹)

 

  • 因為class 是Python 中受保護的關鍵字。也就是說,class 是Python 語言的保留字,在Python 程式裡是不能當作變數或引數名使用的(和前面介紹的BeautifulSoup.findAll() 裡的keyword 無關)另外,你也可以用屬性引數把class 用引號包起來:
    bsObj.findAll("", {"class":"green"})

正則:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re, requests

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html, "html.parser")
images = bsObj.findAll("img", {"src":re.compile("\.\.\/img\/gifts/img.*\.jpg")})
for image in images: 
    print(image["src"])

 Lambda 表示式,下面的程式碼就是獲取有兩個屬性的標籤:
 soup.findAll(lambda tag: len(tag.attrs) == 2)
這行程式碼會找出下面的標籤:
 <div class="body" id="content"></div>
 <span style="color:red" class="title"></span>
如果你願意多寫一點兒程式碼,那麼在BeautifulSoup 裡用Lambda 表示式選擇標籤,將是正規表示式的完美替代方案。


遍歷陣列可以直接tag[3],直接陣列下標取值。

 

BeautifulSoup 物件查詢你想要的資訊,比直接在 HTML 文字里查詢信 息要簡單得多。通常在你準備列印、儲存和運算元據時,應該最後才使 用 .get_text()。一般情況下,你應該儘可能地保留 HTML 文件的標籤結構。               bs4結合正則更厲害哦

 

重定向(redirect)允許一個網頁在不同的域名下顯示。重定向有兩種形式:

1 、伺服器端重定向,網頁在載入之前先改變了 URL; 

2 、客戶端重定向,有時你會在網頁上看到“10 秒鐘後頁面自動跳轉到……”之類的訊息, 表示在跳轉到新 URL 之前網頁需要載入內容。

 

開始採集

對獲取連結多觀察,尋找最好方法!

Scrapy 就是一個幫你大幅度降低網頁連結查詢和識別工作複雜度的 Python 庫,它可以讓你輕鬆地採集一個或多個域名的資訊。不過目前 Scrapy 僅支援 Python 2.7,還不支援Python 3.x。

使用API(和其他網站結合,呼叫資料)

    究竟 API 和普通的網址訪問有什麼區別呢?如果不考慮 API 高大上的名稱,其實兩者沒啥區別。API 可以通過 HTTP 協議下載檔案,和 URL 訪問網站獲取資料的協議一樣,它幾乎可以實現所有在網上乾的事情。API 之所以叫 API 而不是叫網站的原因,其實

是首先 API 請求使用非常嚴謹的語法,其次 API 用 JSON 或 XML 格式表示資料,而不是HTML 格式。

輸入ip看國家:

import json
from urllib.request import urlopen

def getCountry(ipAddress):
    response = urlopen("http://freegeoip.net/json/"+ipAddress).read().decode('utf-8')
    responseJson = json.loads(response)
    return responseJson.get("country_code")
print(getCountry("50.78.253.58"))

儲存資料

媒體檔案
儲存媒體檔案有兩種主要的方式:只獲取檔案URL 連結,或者直接把原始檔下載下來

 

把資料儲存到CSV
CSV(Comma-Separated Values,逗號分隔值)是儲存表格資料的常用檔案格式。Microsoft
Excel 和很多應用都支援CSV 格式,因為它很簡潔。下面就是一個CSV 檔案的例子:
fruit,cost
apple,1.00

MySQL(Navicat for MySQL神器)

“關係型資料”就是有關聯的資料。就是這麼簡單!

 

每個欄位定義由三部分組成:
• 名稱( id 、 title 、 created 等)
• 資料型別( BIGINT(7) 、 VARCHAR 、 TIMESTAMP )
• 其他可選屬性( NOT NULL AUTO_INCREMENT )

有一些技巧你其實可以很快地學會,它們可以讓你的資料庫變得更高效:

  1. 給每個資料表都增加一個 id 欄位
  2. 用智慧索引。字典(指的是常用的工具書,不是指 Python 的字典物件)是按照字母順序排列的單詞表
  3. 最後一點是關於資料查詢時間和資料庫空間的問題。一個常見的誤區就是在資料庫中儲存大量重複資料,尤其是在做大量自然語言資料的網路資料採集任務時。如果把這些資料分成三個表,你就可以看到資料庫佔用的空間會大大降低,雖然表定義的結構變複雜了,但是新增的欄位就是 id 欄位。它們是整數,不會佔用很多空間。另外,每個 URL 和片語都只會儲存一次。(大塊化小,id佔記憶體小

讀取文件

txt    csv    pdf    word

高階資料採集

你將掌握如何用網路爬蟲測試網站,自動化處理,以及通過更多的方式接入網路。最後你將學到一些資料採集的工具,幫助你在不同的環境中收集和操作任意型別的網路資料,深入網際網路的每個角落。

資料清洗

高階資料採集
def ngrams(input, n):
content = re.sub('\n+', " ", content)
content = re.sub(' +', " ", content)
content = bytes(content, "UTF-8")
content = content.decode("ascii", "ignore")
print(content)
input = input.split(' ')
output = []
for i in range(len(input)-n+1):
output.append(input[i:i+n])
return output
這裡首先把內容中的換行符(或者多個換行符)替換成空格,然後把連續的多個空格替換成一個空格,確保所有單詞之間只有一個空格。最後,把內容轉換成 UTF-8 格式以消除轉義字元。

 

自然語言處理

穿越網頁表單與登入視窗進行採集

Requests 庫(http://www.python-requests.org/)就是這樣一個擅長處理那些複雜的HTTP 請
求、cookie、header(響應頭和請求頭)等內容的Python 第三方庫。

採集JavaScript

影像識別與文書處理

 

避開採集陷阱

遠端採集

 

《Python之禪》 Tim Peters

優美勝於醜陋

明瞭勝於隱晦

簡潔勝於複雜

複雜勝於混亂

扁平勝於巢狀

寬鬆勝於緊湊

可讀性很重要

即便是特例,也不可違背這些規則

雖然現實往往不那麼完美

但是不應該放過任何異常

除非你確定需要如此

如果存在多種可能,不要猜測

肯定有一種——通常也是唯一一種——最佳的解決方案

雖然這並不容易,因為你不是Python之父1

動手比不動手要好

但不假思索就動手還不如不做

如果你的方案很難懂,那肯定不是一個好方案

如果你的方案很好懂,那肯定是一個好方案

名稱空間非常有用,我們應當多加利用

 

 

相關文章