爬蟲教程(1)基礎入門
爬蟲介紹
網路爬蟲,英譯為 web crawler ,是一種自動化程式,現在我們很幸運,生處網際網路時代,有大量的資訊在網路上都可以查得到,但是有時我們需要網路上的資料,活著文章,圖片等等,但是,一個個地複製,貼上是不是太傻了,循著 “DRY” 的設計原則,我們希望用一個自動化的程式,自動幫我們匹配到網路上面的資料,然後下載下來,為我們所用。
其中,搜尋引擎就是個很好的例子,搜尋引擎技術裡面大量使用爬蟲,他爬取下整個網際網路的內容,儲存在資料庫裡面,做索引。
爬蟲思路
首先,我們要知道,每一個網頁都是一份 HTML
文件,全稱叫 hypertext
markup language
,是一種文字標記語言,他長的就像這樣:
<html>
<head>
<title>首頁</title>
</head>
<body>
<h1>我是標題</h1>
<img src="xxx">
</body>
</html>
由上,我們可以看出,這是一份很有規則的文件寫法
我們開啟一個網頁,即是通過了 HTTP
協議,對一個資源進行了請求,如何他返還你一份 HTML
文件,然後瀏覽器進行文件的渲染,這樣,你就看到一份美麗的網頁啦
所以,我們只需要模擬瀏覽器,傳送一份請求,獲得這份文件,再抽取出我們需要的內容就好
簡單爬蟲
我們使用python語言,因為python語言的網路庫非常多,而且社群對於爬蟲的建設非常好,現在很多情況下,大家說起爬蟲,第一個想到的就是python,而且,當年GOOGLE的部分爬蟲也是使用python編的,只不過後面轉去了C++,這也說麼python對爬蟲是得天獨厚的
那麼,我們來寫一個最簡單的爬蟲:
import urllib2
response=urllib.urlopen("http://xxx.com")
- 首先,我們引入python的urllib庫
- 然後,我們對一個url地址進行反問
這樣,只要我們執行:
print response.read()
我們就可以看到,一版面的 HTML
進階1
對於一般網站,其實,剛剛那樣的程式就夠用了,但是,網頁裡面的資料對於很對網際網路企業也很寶貴,所以,她們並不想讓你隨意拿走,他要做一些手腳,防止你爬取
對於這重情況,我們的唯一辦法就是讓自己裝的更像瀏覽器
首先,我們來看看一個簡單的請求
可以看見,我們的一個訪問,包含了很多資訊,通常我們必須要偽裝的就是 User-Agent
了
我們的手法是這樣的:
import urllib2
header={
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Host":"aljun.me"
}
request=urllib2.request("http://xxx.com",header=header)
response=urllib2.urlopen(request)
- 我們先偽造了我們請求頭請求,然後再發送我們的請求,這樣做的就好像真的是瀏覽器傳送的一樣
但是啊,有時候,我們會遇到一個東西,叫做cookie
,如果你熟悉網際網路發展時,就會知道,這個是網景公司推出的一種想法,他能在使用者瀏覽器用儲存資訊,這樣就做到了登入主場購物車等等操作的瀏覽器回話,就能夠確認訪問者的身份
那麼我們要怎麼樣做,才能把我們的cookie傳送過去呢?
import urllib2
import cookielib
cookie={"bdshare_firstime":1455378744638}
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
urllib2.install_opener(opener)
response=urllib2.urlopen("http://xxx.com")
- 這樣我們就構造了一個cookie傳送過去,不過我最近遇到需要cookie的情況比較少,而且真正需要cookie的時候,其實互動還是很多的,單一的構造cookie請求我感覺是不夠的
現在我們可以傳送cookie了,那麼又迎來了另一個問題,我們一直在使用沒有引數的訪問方法,想象一下,以往我們訪問網頁,有時是需要輸入幾個登陸框,或者評論框的,這樣我們才能有資料互動
其實這個也很簡單,我們可以這麼寫:
import urllib2
data={
"username":"xxx"
"password":"xxx"
}
request=urllib2.request("http://xxx.com",data)
response=urllib2.urlopen(request)
這樣做便可以了,那麼組合以上我們的操作,我們就基本可以訪問一切我們想要訪問的網頁,獲得一份 HTML
文件了
爬取圖片
突然發現,若只是獲得文字型別的HTML文件,好像很無聊,那麼我們應該怎麼樣下載到我們的圖片呢?
首先,你要知道,圖片是有地址的,比如
http://zhaduixueshe.com/static/pic/discovery.png
可以看出,他也是一個檔案型別,只要對他進行HTTP訪問,我們一樣能拿到資料,一樣可以下載下來
比較暴力的辦法:
import urllib2
response=urllib2.urlopen("http://zhaduixueshe.com/static/pic/discovery.png")
with open("xxx.png","wb") as f:
f.write(response.read())
這樣確實可以成功的下載圖片,但是比較暴力
那麼我們可以溫柔一點,因為有時圖片較大,這樣下載很容易出現錯誤,這個時候我們需要快取的幫助
import urllib2
import stringIO
response=urllib.urlopen("http://zhaduixueshe.com/static/pic/discovery.png")
response=stringIO.stringIO(response.read())
with open("xxx.png","wb") as f:
f.write(response)
而且這樣的做法,還可以使用PIL
模組,對下下來的圖片進行渲染活著整理
那麼,最好用的下載圖片的辦法是什麼呢?
import urllib
path="xxx.png"
url="http://zhaduixueshe.com/static/pic/discovery.png"
urllib.urlretrieve(url,path)
這是官方推薦做法,非常快,而且好用。
requests
這個世界上,總有那麼一些人,他們不滿現狀,積極進取,python內建的urllib
和urllib2
其實已經算是蠻好用了,但是非有人不服,於是他做出了更好的一個http庫,叫做request
Requests: HTTP for Humans
它是以這麼一句話介紹自己的,為人類使用的HTTP庫
下載requests:
pip install requests
他的使用非常之簡單,簡直可以說是弱智
接下來我演示部分他的使用,光是看語句,你便知道他的作用都是什麼
In [1]: import requests
In [3]: response=requests.get("http://aljun.me")
In [4]: response=requests.post("http://zhihu.com/login",data={"username":"xxx"})
等等之類的操作,由於他的文件寫的非常好,我還是比較推薦大家去看看他的官方文件
都爬下來了,然後呢?
通常,我們對於HTML
文件的處理的辦法,比較流行的集中:
- re(正則表示式)
- beautifulsoup
- xpath
- pyquery
re
首先,正則表示式是什麼呢?它是用來匹配文件的,例如
import urllib2
import re
reg=r'http.(d+).jpg'
reg=re.compile(reg)
response=urllib2.urlopen("http://xxx.com")
result=re.findall(response.read(),reg)
這樣我們就得到了我們想要的,符合我們需要的資訊了
但是古話有云:
你遇到了一個問題,你想到使用正則表示式解決它,於是,你現在有了兩個問題
即是說,正則這個東西很厲害,但是不是很好掌握,反正我是從來沒背下來幾個正則表示式匹配模式的
beautifulsoup
這個庫是用來編譯HTML
程式碼的專業庫
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
print(soup.prettify())
###
<html>
<head>
<title>首頁</title>
</head>
<body>
<h1>我是標題</h1>
<img src="xxx">
</body>
</html>
soup.title
# <title>The Dormouse's story</title>
soup.title.name
# u'title'
soup.title.string
# u'The Dormouse's story'
soup.title.parent.name
# u'head'
soup.p
# <p class="title"><b>The Dormouse's story</b></p>
soup.p['class']
# u'title'
soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
soup.find_all('a')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
是不是有一種要什麼有什麼的感覺
之後的xpath,我在之前的教程裡面有介紹過了,
pyquery
pyquery是以jquery的選擇器語法為基礎,非常適合前端轉來的
>>> from pyquery import PyQuery as pq
>>> from lxml import etree
>>> import urllib
>>> d = pq("<html></html>")
>>> d = pq(etree.fromstring("<html></html>"))
>>> d = pq(url=your_url)
>>> d = pq(url=your_url,
... opener=lambda url, **kw: urlopen(url).read())
>>> d = pq(filename=path_to_html_file)
>>> d("#hello")
[<p#hello.hello>]
>>> p = d("#hello")
>>> print(p.html())
Hello world !
>>> p.html("you know <a href='http://python.org/'>Python</a> rocks")
[<p#hello.hello>]
>>> print(p.html())
you know <a href="http://python.org/">Python</a> rocks
>>> print(p.text())
you know Python rocks
呼叫json格式
前面我們說到了網路資源不僅僅是HTML
,還有一種格式叫json檔案
它是javascript面向物件表示式的意思
很多網站都會提供api,也就是資料介面,一般都是以json格式返回的,我的部落格的like返回也是json格式的檔案
In [1]: import urllib2
In [2]: response=urllib2.urlopen("http://aljun.me/like")
In [3]: print response.read()
{
"liked": 1647
}
我可以良好的使用json包,來對這個檔案進行解析,因為json格式和python自帶的dict檔案形式很像,所以,這個非常簡單