1. 程式人生 > >爬蟲教程(1)基礎入門

爬蟲教程(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

程式碼了,就是這麼簡單,使用python

進階1

對於一般網站,其實,剛剛那樣的程式就夠用了,但是,網頁裡面的資料對於很對網際網路企業也很寶貴,所以,她們並不想讓你隨意拿走,他要做一些手腳,防止你爬取

對於這重情況,我們的唯一辦法就是讓自己裝的更像瀏覽器

首先,我們來看看一個簡單的請求

pic

可以看見,我們的一個訪問,包含了很多資訊,通常我們必須要偽裝的就是 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內建的urlliburllib2其實已經算是蠻好用了,但是非有人不服,於是他做出了更好的一個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檔案形式很像,所以,這個非常簡單