首先先申請一個Koding帳號
申請完之後,Koding會帶你進入平常的工作環境,但還沒有驗證前,什麼都不能操作
此時,可以重新整理此頁,會出現輸入驗證碼的對話框
將信箱收到的驗證碼填入,就可以開啟Koding的VM環境
稍作一會等待,即可進入工作畫面,Koding提供了GUI IDE編輯介面及Terminal
在Terminal畫面中輸入以下這幾句,安裝MySQLdb、lxml以及mechanize
sudo apt-get update
sudo apt-get install python-mysqldb
sudo apt-get install libxml2-dev libxslt-dev python-dev
sudo apt-get install python-lxml
sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install mechanize
最後你可以在Terminal輸入python進入 python 的編譯環境,輸入以下幾行,都沒有顯示錯誤即代表安裝成功
from lxml import etree
import mechanize
import MySQLdb
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
[lxml]
page = etree.HTML(html)
for i in page.xpath(u"XPath語法"):
print i
[XPath語法]
找出所有連結的網址(a的href屬性)//a/@href
找出所有連結的文字//a/text()
找出div屬性id='txt'的物件//div[@id='txt']
找出td屬性class包含'GridItem'字串的物件//td[contains(@class, 'GridItem')]
- class有多個value:
<td class="GridItem td1">
- 相似value的比對:同時抓取
<td class="GridItem1">
、<td class="GridItem2">
...
找出font屬性color='#0000ff'或是屬性color='blue的'物件//font[(@color="#0000ff" or @color="blue")]
找出font屬性color='#0000ff'或是span屬性style="COLOR: blue"的物件
//font[@color="#0000ff"] | //span[@style="COLOR: blue"]
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
延續之前抓取 http://blog.marsw.tw 網頁的例子,以下示範抓取該網頁其中一篇內文
[程式碼]
# encoding: utf-8
import urllib2
from lxml import etree
from HTMLParser import HTMLParser
class MLStripper(HTMLParser):
def __init__(self):
self.reset()
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)
def strip_tags(html):
try:
s = MLStripper()
s.feed(html)
return s.get_data()
except:
return html
request = urllib2.Request("http://blog.marsw.tw/2013/04/blog-post_9395.html")
response = urllib2.urlopen(request)
html = response.read()
page = etree.HTML(html)
fileout1 = file('06_v1.txt','w')
fileout1.write(("".join(page.xpath(u"//div[@class='post-body entry-content']/descendant::text()"))).encode('utf8'))
fileout1.close()
fileout2 = file('06_v2.txt','w')
fileout2.write(("".join(page.xpath(u"//div[contains(@class, 'post-body')]/descendant::text()"))).encode('utf8'))
fileout2.close()
raw_html = etree.tostring(page.xpath(u"//div[contains(@class, 'post-body')]")[0], pretty_print=True,encoding='UTF-8')
text = strip_tags(raw_html)
fileout3 = file('06_v3.txt','w')
fileout3.write(text)
fileout3.close()
[程式說明]
我們觀察部落格文章的格式,發覺內文是包在div中,
v1的寫法是把完整class的value寫出來,而v2的寫法只要寫class其中一個value
v1、v2的寫法都是利用XPath Axes的概念將article底下不管幾階(descendant)所有的文字印出
而v3的寫法則是將article這個標籤所包含的所有原始html以raw_html這個變數儲存
再以strip_tags函式將raw_html中所有的html標籤去除,以text來儲存並輸出
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
延續之前抓取 http://blog.marsw.tw 網頁的例子,以下示範抓取該網頁文章的標題
[程式碼]
# encoding: utf-8
import urllib2
from lxml import etree
request = urllib2.Request("http://blog.marsw.tw")
response = urllib2.urlopen(request)
html = response.read()
page = etree.HTML(html)
print "v1-------"
for i in page.xpath(u"//h5/a"):
print i.text
print "v2-------"
for i in page.xpath(u"//h5/a/text()"):
print i
print "v3-------"
for i in page.xpath(u"//article/header/h5/a/text()"):
print i
print "v4-------"
for i in page.xpath(u"//article"):
print i.xpath(u"descendant::h5/a/text()")[0]
[程式說明]
我們可以從開發人員工具可以看到,網頁文章的標題是在h5下的a的文字,v1、v2兩種寫法都可以
而v4的寫法是配合XPath Axes的概念,
因為一般來說XPath會寫完整的路徑,也就是v3的//article/header/h5/a/text()
寫法
但我們在處理網頁中,有些網頁的格式並不是這麼漂亮,就可以透過XPath的父子屬性來寫
v4的寫法是指我將article的所有子孫(descendant)中h5下的a的第1個文字印出
會用descendant而不是child是因為不確定h5是不是就在article底下一層,在不確定階層樹的狀況,就採用descendant
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
延續之前抓取 http://blog.marsw.tw 網頁的例子
這裡示範如何把該頁的圖片存取下來的方法:
我們利用lxml這個額外的module來快速處理html來獲取我們想要的資訊
而lxml所使用的是xpath的語法
[程式碼]
# encoding: utf-8
import urllib2
from lxml import etree
request = urllib2.Request("http://blog.marsw.tw")
response = urllib2.urlopen(request)
html = response.read()
page = etree.HTML(html)
count = 0
for url in page.xpath(u"//img/@src"):
if url.startswith("http:"):
print url
try:
img_request = urllib2.Request(url)
img_response = urllib2.urlopen(img_request)
img = img_response.read()
except:
continue
count = count+1
filename = str(count)+".jpg"
pic_out = file(filename,'w')
pic_out.write(img)
pic_out.close()
[程式說明]
想要抓圖片,首先要先獲得圖片的url,
而html tag中,圖片的url是記錄在img這個tag的src屬性
因此lxml的語法,找出所有img tag的src屬性寫法就是//img/@src
,並且以unicode編碼
找出開頭是http的src url(其他是用相對路徑,無法直接存取該圖),之後就對該圖片做存取的動作,
同時為了避免該圖的連結失效,而造成程式中斷,因此加上了try/except的機制
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
這裡介紹以Python自帶的模組 urllib2 開發抓取MoneyDJ的人氣指數的爬蟲
[程式碼]
# encoding: utf-8
import urllib,urllib2
url = "http://www.moneydj.com/InfoSvc/apis/vc"
request = urllib2.Request(url)
request.add_header("Content-Type","application/json")
payload = '{"counts":[{"svc":"NV","guid":"a180a15b-9e4f-4575-b28f-927fcb5c63a3"}]}'
response = urllib2.urlopen(request,data=payload)
html = response.read()
print html
輸出結果
{"counts":[{"count":3609,"guid":"a180a15b-9e4f-4575-b28f-927fcb5c63a3","svc":"NV"}]}
[程式說明]
在這個範例程式中,我們要抓取MoneyDJ的人氣指數
由於此網頁的人氣指數並不是直接輸出在html原始碼中(原始碼的是假人氣資料)
而是另外透過http://www.moneydj.com/InfoSvc/apis/vc 這隻 api 去產生真實的人氣指數
且透過開發人員工具,我們也可以看到 request header 的 Content-Type 為 json
而此API是透過POST的方式傳遞資料,
我們直接將 Request Payload 的資料複製貼上(按下view source會產生程式內的格式)
程式輸出的結果就有包含正確的人氣指數3609
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
這裡介紹以Python自帶的模組 urllib、urllib2 開發高鐵時刻查詢的爬蟲
[程式碼]
以下的程式實作以POST
方法向 高鐵時刻查詢網站 發送一個Request
並加入User-Agent的header,將這隻爬蟲偽裝成Mac系統的Chorme瀏覽器
獲得response後,取得該網址的 html 原始碼,存成一個名為02_thsrc.html的檔案
# encoding: utf-8
import urllib,urllib2
url = "http://www.thsrc.com.tw/tw/TimeTable/SearchResult"
request = urllib2.Request(url)
request.add_header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36")
form_data = {
"StartStation": "977abb69-413a-4ccf-a109-0272c24fd490",
"EndStation": "f2519629-5973-4d08-913b-479cce78a356",
"SearchDate": "2016/01/10",
"SearchTime": "17:00",
"SearchWay":"DepartureInMandarin",
"RestTime":"",
"EarlyOrLater":""
}
form_data = urllib.urlencode(form_data)
response = urllib2.urlopen(request,data=form_data)
html = response.read()
file_out = file("02_thsrc.html",'w')
file_out.write(html)
file_out.close()
[程式說明]
在這個範例程式中,我們要查詢的是從台北到左營2016/01/10 17:00出發可能班次
從Chrome開發人員工具可以看到高鐵時刻查詢
是以POST方式發送request,也可以看到Form Data的樣貌
另外,我們從開發人員工具中看到的Form Data的格式並不是真正向Server發送的格式,
利用view URL encoded
看到的才是真正的格式
在程式中form_data是以dictionary的方式儲存資料,
在傳送時需要透過urllib這個module來做urlencode才能當成最後傳送出去的資料
而高鐵網站會檢查發送request的對象,若為爬蟲程式會阻擋,
因次我們需要將此爬蟲程式偽裝成瀏覽器
也就是在header中的User-Agent屬性加上資料
這個值可以從Chrome開發人員工具中Network看到的User-Agent直接複製
{替換查詢內容}
從Form Data大概看得出2016/01/10、17:00的資訊,
但起訖站卻沒有看到「台北」跟「左營」這兩個關鍵字,
我們可以從StartStation、EndStation這兩個名稱猜測,這兩個特殊的編碼應該分別代表「台北」跟「左營」
利用檢查元素的方式,可以看到在開發人員工具中,各站名的value,也就是這些特殊的編碼
也可以看到以出發時間查詢的value是DepartureInMandarin
若要查詢其他地區或是改成以抵達時間的查詢方式就可用這些value來替換
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
其實爬蟲的技巧主要就是觀察
觀察你想要抓的資料有沒有什麼規則
:
- 哪個網址才是真的資料所在
- 想要抓的元素是以什麼tag分隔
瀏覽器就有功能可以幫我們觀察這些資訊
我們想要知道這個網址request的方法是GET還是POST
以chrome為例:
1.開啟開發人員工具
,進到Network
標籤:
2.重新整理網頁,通常我們要抓取的網頁會在最上方:
我們就可以知道要獲取 http://blog.marsw.tw 的資料,request方法是GET
而像高鐵時刻查詢的網頁request方法是POST:
也能知道request header該放怎麼樣的資訊:
以及POST該傳怎樣的內容及格式:
3.而原始碼除了可以重爬蟲程式抓取後的資料觀察,Chrome的檢視網頁原始碼
功能也可以幫助我們先行看到抓取的資料原貌
4.而想要抓取的元素tag也可以從Chrome觀察,對著想要的元素按右鍵>檢查
假設這裡我是想抓取每篇文章的標題,我就對著標題按下右鍵>檢查
點選任一區塊原始碼時,Chrome顯示該程式碼在網頁上顯示的區塊位置
這裡我猜測應該是h5這個tag底下的內容會是我想要的資訊,我點選過後,Chrome顯示的的確是標題區塊
ps.有個Chrome套件InfoLite可以簡單幫忙確認所點選的程式碼是否適用我們想抓的資料規則,
以此例來說,我開啟InfoLite後,點選標題,他在上方產生了 .entry-title
,
畫面上顯示header h5
代表著這些標題的DOM是 header>h5,而h5的class屬性是entry-title
(.
代表的是class #
代表的是id)
我們也可以看到這個規則下,的確是所有的文章標題
但有時抓取的資料不一定都以class、id等tag標明不同的內容時,
就還是得仰賴直接觀察原始碼,用程式對觀察到的規則做解析,才能確定該規則是不是我們想要的內容
這裡介紹的方式是利用安裝 Python時附的 urllib2 module來實作
可以不需要安裝任何新的module就可以實作一支最基本的爬蟲
[程式碼]
以下的程式實作以GET
方法向 http://blog.marsw.tw 發送一個Request
獲得response後,取得該網址的 html 原始碼
將html原始碼印出,及存成一個名為01_blog.html的檔案
# encoding: utf-8
import urllib2
request = urllib2.Request("http://blog.marsw.tw")
response = urllib2.urlopen(request)
html = response.read()
print html
fileout = file("01_blog.html","w")
fileout.write(html)
fileout.close()
[程式說明]
urlopen後面可以接一個 url 或是一個 Request 物件
所以原程式(第1種寫法)
request = urllib2.Request("http://blog.marsw.tw")
response = urllib2.urlopen(request)
也可以改寫成(第2種寫法)
response = urllib2.urlopen("http://blog.marsw.tw")
而程式碼會習慣這樣寫的原因是在實戰中,會遇到許多不同的案例
這時需要修改一些Request的設定,才能順利抓取我們想要的資料
因此就習慣還是會用第1種寫法來實作
爬蟲系列教學文目錄
爬蟲系列教學文程式碼
安裝Python及Python常用語法可參考 Python - 十分鐘入門
[背景知識]
[前言]
採用各module原因(待補)
[Crawler - urllib2]
用GET方法抓取網頁
觀察技巧 with Chrome開發人員工具
用POST方法與偽裝User-Agent抓取網頁
處理不同的Content-Type
[Parsing - lxml]
抓取網頁所有圖片
抓取網頁標題 & XPath Axes說明
抓取網頁純文字內文
lxml、XPath 常用語法
big5編碼處理,unicode,url編碼
json
[Crawler - 身分驗證]
cookie
mechanize
[資料庫 - MySQLdb]
[加速 - multiprocessing]
[環境安裝]
如何在koding上搭建爬蟲環境(MySQLdb、lxml、mechanize)