網頁

2010年2月16日 星期二

以 POST Method 發布訊息

機器人收進訊息之後我們期望它能做出一些回應,其中 Post Method 是網路上常見的發表訊息的方法可將網頁上的表格回傳至伺服器端。

以下提供一個簡單的網頁做示範 post.php

<html>
 <head>
 </head>
 <body>
  <?php if ($_POST) {echo "<p>Hi ".$_POST[Name]." !</p>";} ?>
  <form id="Post_DEMO" name="Form_DEMO" method="post" action="post.php">
   <h1>Nice to meet you. I am POST_DEMO!</h1>
   <h2>What is your name?</h2>
   <input type="text" name="Name" id="Name" />
   <input type="submit" name="button" id="button" value="Confirmed" />
  </form>
 </body>
</html>

基本上這是一個打招呼的網頁,網頁中有一個表單讓使用者填入自己的名字,送出表單後網頁會重新載入並顯示 Hi "使用者名字" 的訊息,當然機器人應該也能跟網頁打招呼,於是借助 curl 的 POST 工能,在 setopt 時增加 POST 以及 POSTFIELD 的設定讓機器人也能送出表單。

假設 post.php 路徑為 http://www.mypage.tw/post.php ,Post 機器人如下:

#! /usr/bin/env python
import pycurl

class GetPage:
    def __init__ (self, url):
        self.contents = ''
        self.url = url

    def read_page (self, buf):
        self.contents = self.contents + buf

    def show_page (self):
        print self.contents

class GetPageByFakeBrowser(GetPage):
    def __init__ (self, url, ua):
        self.contents = ''
        self.url = url
        self.ua = ua

mypage = GetPageByFakeBrowser( \
"http://www.mypage.tw/post.php", \
"Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00")
testcurl = pycurl.Curl()
testcurl.setopt(testcurl.URL, mypage.url)
testcurl.setopt(testcurl.USERAGENT, mypage.ua)
testcurl.setopt(testcurl.WRITEFUNCTION, mypage.read_page)
testcurl.perform()
testcurl.setopt(testcurl.POST, 1)
testcurl.setopt(testcurl.POSTFIELDS, "Name=Robot&button=confirmed")
testcurl.perform()
testcurl.close()
mypage.show_page()

如此一來機器人就有讀取網頁以及送出表單的功能,接下來我們希望它能做一些較複雜的事情。

使用 python + curl 取得網頁內容(2)

當我們取得整個網頁的 html 文件後,接下來就是從 html 中取得我們有興趣的訊息,例如可以搜尋 a 標籤來取得網頁中的連結,以下範例從 http://chobill.twbbs.org/blog/ 網頁中取得所有連結,以 GetPageByFakeBrowser 取得網頁內容,接著使用 URLParser 將網頁連結過濾出來:

#! /usr/bin/env python
import pycurl

class GetPage:
    def __init__ (self, url):
        self.contents =''
        self.url = url

    def read_page (self, buf):
        self.contents = self.contents + buf

    def show_page (self):
        print self.contents

class GetPageByFakeBrowser(GetPage):
    def __init__ (self, url, ua):
        self.contents = ''
        self.url = url
        self.ua = ua

import HTMLParser
class URLParser(HTMLParser.HTMLParser):
    def __init__(self):
        HTMLParser.HTMLParser.__init__(self)
        self.urls = []

    def handle_starttag(self, tag, attributes):
        if tag != 'a': return
        for name, value in attributes:
            if name == 'href' and value not in self.urls:
                self.urls.append (value)

mypage = GetPageByFakeBrowser( \
"http://chobill.twbbs.org/blog/", \
"Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00")
testcurl = pycurl.Curl()
testcurl.setopt(testcurl.URL, mypage.url)
testcurl.setopt(testcurl.USERAGENT, mypage.ua)
testcurl.setopt(testcurl.WRITEFUNCTION, mypage.read_page)
testcurl.perform()
testcurl.close()
parser = URLParser()
parser.feed ( mypage.contents )
parser.close()
for url in parser.urls:
    print url 
然而這個程式在許多情況下並不管用,因為這世界上存在許多撰寫的相當"有藝術"或是加入一些直譯語言的網頁,它們會讓這支程式在處理 html 文件時出錯,我們之後會回過頭來修正這些問題。

2010年2月8日 星期一

使用 python + curl 取得網頁內容(1)

為了讓機器人能從網路上搜尋資訊第一步就是讓機器人程式取得網頁的內容,我們可以利用 curl 這個函式庫來幫我們處理取得網頁,事實上 curl 能做的事情很多它能做 HTTP、HTTPS 細部設定並且支援多種協定如 Telnet、FTP、SCP 以及 LDAP 等,是很方便的工具。

以下是一段 python 程式,它的功能是用來取得 http://robotexp.blogspot.com/ 也就是本站的內容

#! /usr/bin/env python
import pycurl

class GetPage:
    def __init__ (self, url):
        self.contents = ''
        self.url = url

    def read_page (self, buf):
        self.contents = self.contents + buf

    def show_page (self):
        print self.contents

mypage = GetPage("http://robotexp.blogspot.com/")
testcurl = pycurl.Curl()
testcurl.setopt(testcurl.URL, mypage.url)
testcurl.setopt(testcurl.WRITEFUNCTION, mypage.read_page)
testcurl.perform()
testcurl.close()
mypage.show_page()

執行這支程式時會將整個頁面 html 下載並顯示在終端機上,然而我們希望 curl 讀取網頁時它的行為能更像一般瀏覽器,首先我們希望它向網站發出 Request 時做一些偽裝。
以下為利用 wireshark 擷取 pycurl 預設的 GET Request:
GET / HTTP/1.1
User-Agent: PycURL/7.19.5
Host: robotexp.blogspot.com
Accept: */*

實際上網頁伺服器會紀錄這些 Request 訊息,伺服器管理者可以從這段訊息的 User-Agent 得知使用者以哪種瀏覽器瀏覽網頁,而 User-Agent: PycURL/7.19.5 很明顯暴露使用者不是以瀏覽器來瀏覽網頁,因此必須修改 curl 的 User-Agent 設定使它看起來像一般瀏覽器,以下我們就讓 curl 偽裝成 Opera 吧!
 
將先前的程式碼修改如下,即可將 User-Agent 訊息置換成 Opera:

#! /usr/bin/env python
import pycurl

class GetPage:
    def __init__ (self, url):
        self.contents = ''
        self.url = url

    def read_page (self, buf):
        self.contents = self.contents + buf

    def show_page (self):
        print self.contents

class GetPageByFakeBrowser(GetPage):
    def __init__ (self, url, ua):
        self.contents = ''
        self.url = url
        self.ua = ua

mypage = GetPageByFakeBrowser( \
"http://robotexp.blogspot.com/", \
"Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00")
testcurl = pycurl.Curl()
testcurl.setopt(testcurl.URL, mypage.url)
testcurl.setopt(testcurl.USERAGENT, mypage.ua)
testcurl.setopt(testcurl.WRITEFUNCTION, mypage.read_page)
testcurl.perform()
testcurl.close()
mypage.show_page()