爬蟲也就是所謂的網絡數據采集,是一種通過多種手段收集網絡數據的方式,不光是通過與 API 交互(或者直接與瀏覽器交互)的方式。最常用的方法是寫一個自動化程序向網絡服務器請求數據(通常是用 HTML 表單或其他網頁文件),然后對數據進行解析,提取需要的信息。實踐中,網絡數據采集涉及非常廣泛的編程技術和手段,比如數據分析、信息安全等。
要抓取網頁數據,要做的就是向服務器發起請求並獲取響應,而在Python中,我們可以使用urllib2這個庫來實現。
下面是一個發生請求並獲取服務器響應的簡單的例子:
# -*- coding: utf-8 -*-
# 導入urllib2 庫 import urllib2 # 使用urllib2.urlopen()向指定的url發送請求,並返回服務器響應的類文件對象 response = urllib2.urlopen("http://www.baidu.com") # 類文件對象的read()方法可讀取文件全部內容,返回字符串 html = response.read() # 打印字符串(頁面源碼) print html
上面的例子就是一個簡單的爬蟲程序,運行程序后打印的結果就是服務器返回的頁面源碼。其效果和在瀏覽器輸入http://www.baidu.com后查看頁面源碼是一樣的。
使用urlopen()發送請求十分簡單,只需要傳入目標url即可,但是如果需要執行更復雜的操作,必須創建一個 Request 實例來構造請求。
下面是一個使用Request()方法構造請求的簡單的例子:
import urllib2 # url 作為Request()方法的參數,構造並返回一個Request對象 request = urllib2.Request("http://www.baidu.com") # Request對象作為urlopen()方法的參數,發送給服務器並接收響應 response = urllib2.urlopen(request) html = response.read() print html
這個例子的運行結果和上面一樣
使用Request()構造請求時,除了必須要的url參數外還有兩個可選參數data和headers:
data:伴隨url提交的數據
headers:一個字典,包含需要發送的HTTP報頭的鍵值對
先來說一說headers中的User-Agent:
像上面的兩個例子,直接用urllib2給一個網站發送請求的話,確實十分簡單,但是很容易被網站檢測到是爬蟲程序。如果遇到一些不喜歡被程序(非人為訪問)訪問的站點,就有可能會拒絕你的訪問請求。但是如果我們用一個合法的身份(例如模擬瀏覽器)去請求別人網站,情況就會好一些,所以我們就應該給我們的爬蟲程序加上一個身份,就是所謂的User-Agent
。我們可以將爬蟲程序偽裝成一個被公認的瀏覽器,用不同的瀏覽器在發送請求的時候,會有不同的User-Agent頭。 urllib2默認的User-Agent頭為:Python-urllib/x.y(x和y是Python主版本和次版本號,例如 Python-urllib/2.7)
給爬蟲程序添加User-Agent:
import urllib2 url = "http://www.baidu.cn" # User-Agent,可以從網上找,也可以自己使用瀏覽器抓包獲取 header = {"User-Agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0"} # 起構造Request請求, request = urllib2.Request(url, headers = header) # 向服務器發送這個請求 response = urllib2.urlopen(request) html = response.read() print html
我們在程序中添加一個火狐瀏覽器的User-Agent,這樣就可以偽造成瀏覽器進行發送請求。
除了User-Agent,我們還可以在 HTTP Request 中加入特定的 Header,來構造一個完整的HTTP請求消息。
import urllib2 url = "http://www.baidu.cn" # User-Agent header = {"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} request = urllib2.Request(url, headers = header) #也可以通過調用Request.add_header() 添加/修改一個特定的header request.add_header("Connection", "keep-alive") # 也可以通過調用Request.get_header()來查看header信息 # request.get_header(header_name="Connection") response = urllib2.urlopen(requset)
#可以查看響應狀態碼 print response.code html = response.read() print html
為了程序更好地運行,我們可以做一個User-Agent列表,在爬蟲執行時隨機選擇一個User-Agent使用
# -*- coding: utf-8 -*- import urllib2 import random url = "http://www.baidu.cn" # User-Agent列表 ua_list = [ "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52", ] # 隨機選擇一個User-Agent user_agent = random.choice(ua_list) request = urllib2.Request(url) #也可以通過調用Request.add_header() 添加/修改一個特定的header request.add_header("User-Agent", user_agent) # 第一個字母大寫,后面的全部小寫 request.get_header("User-agent") response = urllib2.urlopen(request) html = response.read() print html
這樣每次發送請求就會使用不同的User-Agent。