參考資料
- Python官方文檔
- 知乎相關資料(1) 這篇非常好, 通俗易懂的總覽整個Python學習框架.
- 知乎相關資料(2)
代碼實現(一): 用Python抓取指定頁面
1 #!/usr/bin/env python 2 #encoding:UTF-8 3 import urllib.request 4 5 url = "http://www.baidu.com" 6 data = urllib.request.urlopen(url).read() 7 data = data.decode('UTF-8') 8 print(data)
urllib.request是一個庫, 隸屬urllib. 點此打開官方相關文檔. 官方文檔應該怎么使用呢? 首先點剛剛提到的這個鏈接進去的頁面有urllib的幾個子庫, 我們暫時用到了request, 所以我們先看urllib.request部分. 首先看到的是一句話介紹這個庫是干什么用的:
The urllib.request module defines functions and classes which help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more.
然后把我們代碼中用到的urlopen()函數部分閱讀完.
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False)
重點部分是返回值, 這個函數返回一個 http.client.HTTPResponse 對象, 這個對象又有各種方法, 比如我們用到的read()方法, 這些方法都可以根據官方文檔的鏈接鏈過去. 根據官方文檔所寫, 我用控制台運行完畢上面這個程序后, 又繼續運行如下代碼, 以更熟悉這些亂七八糟的方法是干什么的。
>>> import urllib.request >>> a = urllib.request.urlopen('http://10.54.0.2/OAapp/WebObjects/OAapp.woa') >>> type(a) <class 'http.client.HTTPResponse'> >>> a.geturl() 'http://10.54.0.2/OAapp/WebObjects/OAapp.woa' >>> a.info() <http.client.HTTPMessage object at 0x7f390a3d4780> >>> a.getcode() 200
如果要抓取百度上面搜索關鍵詞為Jecvay Notes的網頁, 則代碼如下
1 #!/usr/bin/env python 2 #encoding:UTF-8 3 import urllib 4 import urllib.request 5 6 data={} 7 data['word']='Jecvay Notes' 8 9 url_values=urllib.parse.urlencode(data) 10 url="http://www.baidu.com/s?" 11 full_url=url+url_values 12 13 data=urllib.request.urlopen(full_url).read() 14 data=data.decode('UTF-8') 15 print(data)
data是一個字典, 然后通過urllib.parse.urlencode()來將data轉換為 'word=Jecvay+Notes'的字符串, 最后和url合並為full_url, 其余和上面那個最簡單的例子相同. 關於urlencode(), 同樣通過官方文檔學習一下他是干什么的. 通過查看
- urllib.parse.urlencode(query, doseq=False, safe='', encoding=None, errors=None)
- urllib.parse.quote_plus(string, safe='', encoding=None, errors=None)
大概知道他是把一個通俗的字符串, 轉化為url格式的字符串。
Python的隊列
在爬蟲程序中, 用到了廣度優先搜索(BFS)算法. 這個算法用到的數據結構就是隊列.
Python的List功能已經足夠完成隊列的功能, 可以用 append() 來向隊尾添加元素, 可以用類似數組的方式來獲取隊首元素, 可以用 pop(0) 來彈出隊首元素. 但是List用來完成隊列功能其實是低效率的, 因為List在隊首使用 pop(0) 和 insert() 都是效率比較低的, Python官方建議使用collection.deque來高效的完成隊列任務.
1 #!/usr/bin/env python 2 #encoding:UTF-8 3 from collections import deque 4 queue = deque(["Eric", "John", "Michael"]) 5 queue.append("Terry") # Terry 入隊 6 print(queue) 7 queue.append("Graham") # Graham 入隊 8 print(queue) 9 queue.popleft() # 隊首元素出隊 10 print(queue) 11 #輸出: 'Eric' 12 queue.popleft() # 隊首元素出隊 13 #輸出: 'John' 14 print(queue) # 隊列中剩下的元素
Python的集合
在爬蟲程序中, 為了不重復爬那些已經爬過的網站, 我們需要把爬過的頁面的url放進集合中, 在每一次要爬某一個url之前, 先看看集合里面是否已經存在. 如果已經存在, 我們就跳過這個url; 如果不存在, 我們先把url放入集合中, 然后再去爬這個頁面。
Python提供了set這種數據結構. set是一種無序的, 不包含重復元素的結構. 一般用來測試是否已經包含了某元素, 或者用來對眾多元素們去重. 與數學中的集合論同樣, 他支持的運算有交, 並, 差, 對稱差.
創建一個set可以用 set() 函數或者花括號 {} . 但是創建一個空集是不能使用一個花括號的, 只能用 set() 函數. 因為一個空的花括號創建的是一個字典數據結構. 以下同樣是Python官網提供的示例。
1 >>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} 2 >>> print(basket) # 這里演示的是去重功能 3 {'orange', 'banana', 'pear', 'apple'} 4 >>> 'orange' in basket # 快速判斷元素是否在集合內 5 True 6 >>> 'crabgrass' in basket 7 False 8 9 >>> # 下面展示兩個集合間的運算. 10 ... 11 >>> a = set('abracadabra') 12 >>> b = set('alacazam') 13 >>> a 14 {'a', 'r', 'b', 'c', 'd'} 15 >>> a - b # 集合a中包含元素 16 {'r', 'd', 'b'} 17 >>> a | b # 集合a或b中包含的所有元素 18 {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'} 19 >>> a & b # 集合a和b中都包含了的元素 20 {'a', 'c'} 21 >>> a ^ b # 不同時包含於a和b的元素 22 {'r', 'd', 'b', 'm', 'z', 'l'}
其實我們只是用到其中的快速判斷元素是否在集合內的功能, 以及集合的並運算。
Requests Module
Requests 是 Python 界大名鼎鼎的一個網絡庫, 其設計哲學是為人類而設計, 所以他提供的功能都非常的人性化. 他的方便對我而言主要有兩大點:
- 對 GET 和 POST 方法的封裝做的很好, 自動處理了編碼等問題;
- 默認開啟了 Cookies 處理, 在處理需要登錄的問題上面非常方便.
Requests 的方便之處不止這兩點, 還提供了諸如標准登錄接口之類的功能, 我們暫時用不上.
總而言之, 對於使用過 urllib 的我們來說, 用 requests 會感覺我們之前生活在石器時代. 第三方庫的強大就在於這里, 這也是 Python 這么火的重要原因.
BeautifulSoup Module
BeautifulSoup 大大方便了我們對抓取的 HTML 數據的解析, 可以用tag, class, id來定位我們想要的東西, 可以直接提取出正文信息, 可以全文搜索, 同樣也支持正則表達式, 相當給力.
小試牛刀
我們隨便抓取一個頁面, 然后用 soup 來解析一下試試他的威力:
1 >>> import requests 2 >>> from bs4 import BeautifulSoup 3 >>> response = requests.get("http://jecvay.com") 4 >>> soup = BeautifulSoup(response.text) 5 6 >>> print(soup.title.text) 7 Jecvay Notes - Good luck & Have fun 8 9 >>> print(soup.body.text) 10 改版策略: 技術博客的真正索引 11 12 上周, 我換掉了我博客的主題, 使用 BootStrap 框架自己寫了一個. 在自己動手寫博客主題之前, 13 我時常時不時到后台主題商店去翻一翻, 想要發現更好看的主題. 挑選有兩種: 14 在一大堆展示面前, 快速瀏覽, 看到亮眼的就仔細看一看是否滿意; 15 自己想好一個目標, 然后用篩選器(或者人肉)篩選出來. 16 閱讀全文 >> (...省略若干) 17 18 >>> for x in soup.findAll("a"): 19 ... print(x['href']) 20 ... 21 http://jecvay.com/2015/02/the-real-index-of-tech-blog.html 22 http://jecvay.com/2015/02/the-real-index-of-tech-blog.html 23 http://jecvay.com/2015/01/wordpress-super-cache.html 24 http://jecvay.com/2015/01/learning-vps-3.html 25 http://jecvay.com/2015/01/nobot-anti-webspider.html 26 http://jecvay.com/2015/01/learning-vps-2.html 27 http://jecvay.com/2014/12/learning-vps-1.html 28 http://jecvay.com/2014/11/what-is-min-cut.html 29 http://jecvay.com/2014/11/compiler-makes-fast-build.html 30 /about-me 31 /archive
我們十分輕松的獲得了全文內容以及所有鏈接.
重訪知乎
在上一篇文章中, 我嘗試使用 urllib 和 re 獲取了知乎登錄頁面的 _xsrf 參數, 這次我們通過這兩個新的模塊再試一次.
打開瀏覽器隱身模式, 打開知乎網, 來到登錄界面, 查看源代碼, 搜索 xsrf 字樣, 得到如下一行:
<input type="hidden" name="_xsrf" value="d4ff8d988193442a774bd0ccff336101"/>
於是我們只要兩行代碼就能搞定:
1 >>> soup = BeautifulSoup(requests.get("http://www.zhihu.com").text) 2 >>> print(soup.find("input", {"name": "_xsrf"})['value']) 3 d4ff8d18b293442a764bd0ccff333601
第三方庫就是這么好用!
