<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>程式設計 遇上 小提琴 &#187; 抓取網頁</title>
	<atom:link href="http://blog.ez2learn.com/tag/%e6%8a%93%e5%8f%96%e7%b6%b2%e9%a0%81/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ez2learn.com</link>
	<description>Victor&#039;s個人部落格，關於程式設計與小提琴</description>
	<lastBuildDate>Tue, 07 Feb 2012 03:26:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>抓網頁的程式庫 : WebChuan</title>
		<link>http://blog.ez2learn.com/2008/10/20/python-module-for-getting-web-webchua/</link>
		<comments>http://blog.ez2learn.com/2008/10/20/python-module-for-getting-web-webchua/#comments</comments>
		<pubDate>Mon, 20 Oct 2008 15:39:28 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Open source]]></category>
		<category><![CDATA[抓取網頁]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=220</guid>
		<description><![CDATA[WebChuan 花了一些時間整理我先前提到設計下所寫出來的抓網頁模組，用Python寫基於Twisted和lxml，可以輕鬆地組織抓取網頁的流程，各種常用的功能都已經有了 我把它命名為WebChuan並且釋放成在MIT License下的Open source project http://webchuan.ez2learn.com/ 有興趣可以參考看看，目前還有很多事要做，包括生成文件、撰寫文件、測試等等，但是先前提到的基本功能都已經完備 http://webchuan.ez2learn.com/wiki/Examples/GetPageTitle 這裡有一個取得網頁標題的簡單程式可以執行看看]]></description>
			<content:encoded><![CDATA[<h1>WebChuan</h1>
<p>花了一些時間整理我先前提到設計下所寫出來的抓網頁模組，用Python寫基於Twisted和lxml，可以輕鬆地組織抓取網頁的流程，各種常用的功能都已經有了</p>
<p>我把它命名為WebChuan並且釋放成在MIT License下的Open source project</p>
<p><a href="http://webchuan.ez2learn.com/">http://webchuan.ez2learn.com/</a></p>
<p>有興趣可以參考看看，目前還有很多事要做，包括生成文件、撰寫文件、測試等等，但是先前提到的基本功能都已經完備</p>
<p><a href="http://webchuan.ez2learn.com/wiki/Examples/GetPageTitle">http://webchuan.ez2learn.com/wiki/Examples/GetPageTitle</a></p>
<p>這裡有一個取得網頁標題的簡單程式可以執行看看</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2008/10/20/python-module-for-getting-web-webchua/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>抓取網頁程式的架構設計</title>
		<link>http://blog.ez2learn.com/2008/10/11/design-of-web-grabing-program/</link>
		<comments>http://blog.ez2learn.com/2008/10/11/design-of-web-grabing-program/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 17:24:54 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[設計]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Open source]]></category>
		<category><![CDATA[抓取網頁]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=138</guid>
		<description><![CDATA[截取網頁的架構設計 我們先前談到了抓取網頁用的工具，但是光有工具是不夠的，良好的設計也是必要的，這次我們就來談談設計 最早我寫一個抓取amazon.com商品資料的程式，當時沒仔細思考設計的問題，而且在一開始低估了問題的複雜程度，導至後來在修改時整個是一團混亂，我把抓取網頁的流程分成幾個部份，然而這些流程之間有著很多細小複雜的溝通和互相依賴的關係，到了後來我發現我哪裡在寫程式，這根本是一團義大利麵! 此時我終於深刻體會到什麼叫漣漪效應，當我修改一小部份程式，有很多依賴此的程式也跟著需要修改，間接依賴的程式片段一樣需要修改，程式的改變有如投入池子中的石子，修改在程式碼間散播開來，再也沒有比這個更糟的設計了，除了修改的問題，測試更是一個嚴重的問題，當我發現一個錯誤，我無法確定這個錯誤到底是屬於誰的，它們之間有這麼多關係，每個人都有嫌疑，我明白這程式繼續寫下去就只有死路一條，於是我開始思考怎樣的設計才是正確的 最明顯的錯誤 最明顯的錯誤就是，流程和流程之間有太多關係了，它們互相依賴，造成藕合度大大提升，牽一髮動全身，因此我意識到每個流程應該都要和其它任何流程沒有任何關係，它們只在乎它們的輸入，以及如何處理它們，於是我就聯想到了責任鏈設計模式，以及工廠的生產線，我想像資料進來，從最先的原料，進入一開始的工廠加工，接著被送到下一個工廠處理，每個工廠只知道如何對進入的產品加工，對於前一個工廠、後一個工廠，對所有工廠都一無所知，這才是將處理流程從藕合的關係中鬆綁的正確設計，於是我做出了設計上的修改，重新寫過了程式，我將幾個大流程分開成獨立的物件，並單獨做測試，確定每個流程都如預期般，有如預期的正確輸出，最後再將這些流程串起來，果然這樣的做法果然解決了問題，但是問題還沒有結束 一直有種強烈的直覺 很多時候沒辦法明白的說出來，但就是有些強烈的直覺，感覺到設計上可以做到某種程度，但卻還無法用言語表達，將每個流程分開程獨立的程式處理，雖然鬆綁藕合，但是卻沒有良好的重用性，到後來我發現Twisted，使用它的Deferred物件，從getPage的Deferred物件中增加parsing的callback，我意識到，不止一個大的流程，從抓取網頁、解析網頁、儲存資料，每一個步驟事實上應該都是獨立的，如果以一大流程做為單位，當我需要使用其它抓取網頁的機制，解析網頁的程式卻要從那個大流程中取出來，很明顯地，以大流程做為單位太大了，而且流程應該是由幾個小步驟組合而成，不應該把它們綁在一起，在這時我還沒有明確的想法，直到&#8230; 遇到GStreamer 為了寫某些程式的需要，我找到了一款Open source的影音串流處理的函式庫，我看到了它Pipeline的機制，此時我眼睛為之一亮，這不就是我想要的設計嗎? 由元素組成串在一起的pipeline，每個元素只有特定處理資料的方式，然後往後面的元素傳 引用自 : http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-bins.html#section-pipeline-img 我的設計 於是我開始構思我的網頁抓取的pipeline，起先我試著模仿它那種pipeline的設計方式，但是它的Element相當複雜，並不適合網頁抓取的pipeline，於是我把心思拉回處理網頁的每個單一步驟該有的特性，最後我做出了這樣的設計 在這其中，我除了考慮到藕合上的問題，同樣也考慮到效率等等的問題，Element本身只專注在於處理資料這件事，資料由input方法輸入，而handleData處理資料，當資料處理完成需要輸出使用outputEvent來通知外界資料處理完成，當資料都處理完成也輸出完成時，就用requestEvent通知外界可以輸入更多資料，然而如果在handleData的過程中發生問題，就使用failureEvent告知外界錯誤訊息，大至上的行為是如此，但在細節上還有一些問題沒想清楚 而Bin本身是一個Element的容器，負責接受來自Element的事件通知，然後做出對應的處理，Pipeline就是一個Bin的子類別，它負責轉送到對應的Element去，或是放入queue中等待request事件再送出，它都使用CallInThread來呼叫element的input方法，這表示，所有工作都是非同步進行的，不需要等一筆資料被處理完成後，才能接受新的資料，只要一個Element的資料處理完，可以馬上再處理下一筆，這是提升效率的方法之一 值得注意的是，Pipeline和Bin本身一樣也是一個Element，這表示它可以被當做Element和其它Element串在一起，或是加入其它Bin中，這讓設計上更有彈性 Retry裝飾者 有了這樣的概念確立後，我引進了更多設計上的應用，例如裝飾者設計樣式，我設計了一個Retry的裝飾者，可以把getPage等等可能會失敗的Element包裝起來，自動進行特定次數的重試，而不必為了getPage特地重寫重試的版本，有其它可能出錯的Element都可以用此裝飾者包裝起來 Dispatcher 然而，到目前為止我們的效能還是不夠好，因為同一個時間裡只有一條pipeline在運行，我們需要的是在同一個時間內可以有多條的pipeline運作，因此設計了一個Dispatcher的Bin，可以新增很多條Pipeline在其中，然後input資料就會自動分派給pipeline If判斷元素 只有這樣還不夠，考慮一下我們如果需要抓取分頁的網頁，我們一頁一頁往下抓，要判斷是否有下一頁，繼續網下抓取或是停止，為此我設計了If判斷用的Element，它會根據一個條件函數來決定輸出的port 當這一切組合在一起 到目前為止所有提到的都是Element，這表示他們可以被替換掉在任何以上的結構中，Dispatcher所分派的對象不一定要是Pipeline，也可以是其它Element，我為了我目前工作用這樣的東西重新組合重寫一次，組合起來像是這樣 而Dispatcher在外面將這個Pipeline重覆了幾次，因此同時可以執行很多個Pipeline，GetPage、Parser等等都是常用的Element，而只有Get book page detail等Element是我們自行設計的Element，這將重覆利用發揮到了極緻，有強大的彈性，你可以在裡面看到一個迴圈，事實上它只是串接著一個If的Element然後Link條件為真的Port和為假的Port到不同元素而已 我最早的設計是如上圖所示，但是後來考慮到Amazon網路書店的Review頁面，往往是商品資料頁面的好幾百倍和千倍，因此，到後來我將商品資料和Review資料的Pipeline分開，分別用Dispatcher包裝起來後串接在一起，Review的Pipeline數量應該要是商品資料的很多倍，如此一來才能更快消化完Review頁面的工作 未來 到此，相信已經可以感受到這樣設計的威力，我希望將我的程式整理成函式庫，釋放出來成為Open source的Project，專案的名字我還在想，目前考慮用中文字"川"或是DStreamer之類的名字，如果有任何想法，也歡迎提供給我 :P 除此之外，如果你有玩過GStreamer，應該知道它有一個用指令來播放串流媒體的功能，像這樣子 gst-launch -v &#8230; <a href="http://blog.ez2learn.com/2008/10/11/design-of-web-grabing-program/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>截取網頁的架構設計</h1>
<p>我們先前談到了抓取網頁用的工具，但是光有工具是不夠的，良好的設計也是必要的，這次我們就來談談設計</p>
<p><span id="more-138"></span></p>
<p>最早我寫一個抓取amazon.com商品資料的程式，當時沒仔細思考設計的問題，而且在一開始低估了問題的複雜程度，導至後來在修改時整個是一團混亂，我把抓取網頁的流程分成幾個部份，然而這些流程之間有著很多細小複雜的溝通和互相依賴的關係，到了後來我發現我哪裡在寫程式，這根本是一團義大利麵! 此時我終於深刻體會到什麼叫漣漪效應，當我修改一小部份程式，有很多依賴此的程式也跟著需要修改，間接依賴的程式片段一樣需要修改，程式的改變有如投入池子中的石子，修改在程式碼間散播開來，再也沒有比這個更糟的設計了，除了修改的問題，測試更是一個嚴重的問題，當我發現一個錯誤，我無法確定這個錯誤到底是屬於誰的，它們之間有這麼多關係，每個人都有嫌疑，我明白這程式繼續寫下去就只有死路一條，於是我開始思考怎樣的設計才是正確的</p>
<h2>最明顯的錯誤</h2>
<p>最明顯的錯誤就是，流程和流程之間有太多關係了，它們互相依賴，造成藕合度大大提升，牽一髮動全身，因此我意識到每個流程應該都要和其它任何流程沒有任何關係，它們只在乎它們的輸入，以及如何處理它們，於是我就聯想到了責任鏈設計模式，以及工廠的生產線，我想像資料進來，從最先的原料，進入一開始的工廠加工，接著被送到下一個工廠處理，每個工廠只知道如何對進入的產品加工，對於前一個工廠、後一個工廠，對所有工廠都一無所知，這才是將處理流程從藕合的關係中鬆綁的正確設計，於是我做出了設計上的修改，重新寫過了程式，我將幾個大流程分開成獨立的物件，並單獨做測試，確定每個流程都如預期般，有如預期的正確輸出，最後再將這些流程串起來，果然這樣的做法果然解決了問題，但是問題還沒有結束</p>
<h2>一直有種強烈的直覺</h2>
<p>很多時候沒辦法明白的說出來，但就是有些強烈的直覺，感覺到設計上可以做到某種程度，但卻還無法用言語表達，將每個流程分開程獨立的程式處理，雖然鬆綁藕合，但是卻沒有良好的重用性，到後來我發現Twisted，使用它的Deferred物件，從getPage的Deferred物件中增加parsing的callback，我意識到，不止一個大的流程，從抓取網頁、解析網頁、儲存資料，每一個步驟事實上應該都是獨立的，如果以一大流程做為單位，當我需要使用其它抓取網頁的機制，解析網頁的程式卻要從那個大流程中取出來，很明顯地，以大流程做為單位太大了，而且流程應該是由幾個小步驟組合而成，不應該把它們綁在一起，在這時我還沒有明確的想法，直到&#8230;</p>
<h2>遇到GStreamer</h2>
<p>為了寫某些程式的需要，我找到了一款Open source的影音串流處理的函式庫，我看到了它Pipeline的機制，此時我眼睛為之一亮，這不就是我想要的設計嗎? 由元素組成串在一起的pipeline，每個元素只有特定處理資料的方式，然後往後面的元素傳</p>
<div id="attachment_140" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/simple-player.png"><img class="size-medium wp-image-140" title="GStreamer的Pipeline" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/simple-player-300x110.png" alt="GStreamer的Pipeline" width="300" height="110" /></a><p class="wp-caption-text">GStreamer的Pipeline</p></div>
<p>引用自 : <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-bins.html#section-pipeline-img">http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-intro-basics-bins.html#section-pipeline-img</a></p>
<h2>我的設計</h2>
<p>於是我開始構思我的網頁抓取的pipeline，起先我試著模仿它那種pipeline的設計方式，但是它的Element相當複雜，並不適合網頁抓取的pipeline，於是我把心思拉回處理網頁的每個單一步驟該有的特性，最後我做出了這樣的設計</p>
<div id="attachment_145" class="wp-caption alignnone" style="width: 278px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/element1.jpg"><img class="size-medium wp-image-145" title="Element 的UML設計圖" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/element1-268x300.jpg" alt="Element 的UML設計圖" width="268" height="300" /></a><p class="wp-caption-text">Element 的UML設計圖</p></div>
<p>在這其中，我除了考慮到藕合上的問題，同樣也考慮到效率等等的問題，Element本身只專注在於處理資料這件事，資料由input方法輸入，而handleData處理資料，當資料處理完成需要輸出使用outputEvent來通知外界資料處理完成，當資料都處理完成也輸出完成時，就用requestEvent通知外界可以輸入更多資料，然而如果在handleData的過程中發生問題，就使用failureEvent告知外界錯誤訊息，大至上的行為是如此，但在細節上還有一些問題沒想清楚</p>
<p>而Bin本身是一個Element的容器，負責接受來自Element的事件通知，然後做出對應的處理，Pipeline就是一個Bin的子類別，它負責轉送到對應的Element去，或是放入queue中等待request事件再送出，它都使用CallInThread來呼叫element的input方法，這表示，所有工作都是非同步進行的，不需要等一筆資料被處理完成後，才能接受新的資料，只要一個Element的資料處理完，可以馬上再處理下一筆，這是提升效率的方法之一</p>
<p>值得注意的是，Pipeline和Bin本身一樣也是一個Element，這表示它可以被當做Element和其它Element串在一起，或是加入其它Bin中，這讓設計上更有彈性</p>
<h2>Retry裝飾者</h2>
<p>有了這樣的概念確立後，我引進了更多設計上的應用，例如裝飾者設計樣式，我設計了一個Retry的裝飾者，可以把getPage等等可能會失敗的Element包裝起來，自動進行特定次數的重試，而不必為了getPage特地重寫重試的版本，有其它可能出錯的Element都可以用此裝飾者包裝起來</p>
<h2>Dispatcher</h2>
<p>然而，到目前為止我們的效能還是不夠好，因為同一個時間裡只有一條pipeline在運行，我們需要的是在同一個時間內可以有多條的pipeline運作，因此設計了一個Dispatcher的Bin，可以新增很多條Pipeline在其中，然後input資料就會自動分派給pipeline</p>
<div id="attachment_147" class="wp-caption alignnone" style="width: 301px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/dispatcheractivity.jpg"><img class="size-medium wp-image-147" title="Dispatcher的活動示意圖" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/dispatcheractivity-291x300.jpg" alt="Dispatcher的活動示意圖" width="291" height="300" /></a><p class="wp-caption-text">Dispatcher的活動示意圖</p></div>
<h2>If判斷元素</h2>
<p>只有這樣還不夠，考慮一下我們如果需要抓取分頁的網頁，我們一頁一頁往下抓，要判斷是否有下一頁，繼續網下抓取或是停止，為此我設計了If判斷用的Element，它會根據一個條件函數來決定輸出的port</p>
<h2>當這一切組合在一起</h2>
<p>到目前為止所有提到的都是Element，這表示他們可以被替換掉在任何以上的結構中，Dispatcher所分派的對象不一定要是Pipeline，也可以是其它Element，我為了我目前工作用這樣的東西重新組合重寫一次，組合起來像是這樣</p>
<div id="attachment_148" class="wp-caption alignnone" style="width: 193px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/activitydiagram1.jpg"><img class="size-medium wp-image-148" title="Amazon 活動圖" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/activitydiagram1-183x300.jpg" alt="Amazon 活動圖" width="183" height="300" /></a><p class="wp-caption-text">Amazon 活動圖</p></div>
<p>而Dispatcher在外面將這個Pipeline重覆了幾次，因此同時可以執行很多個Pipeline，GetPage、Parser等等都是常用的Element，而只有Get book page detail等Element是我們自行設計的Element，這將重覆利用發揮到了極緻，有強大的彈性，你可以在裡面看到一個迴圈，事實上它只是串接著一個If的Element然後Link條件為真的Port和為假的Port到不同元素而已</p>
<p>我最早的設計是如上圖所示，但是後來考慮到Amazon網路書店的Review頁面，往往是商品資料頁面的好幾百倍和千倍，因此，到後來我將商品資料和Review資料的Pipeline分開，分別用Dispatcher包裝起來後串接在一起，Review的Pipeline數量應該要是商品資料的很多倍，如此一來才能更快消化完Review頁面的工作</p>
<h2>未來</h2>
<p>到此，相信已經可以感受到這樣設計的威力，我希望將我的程式整理成函式庫，釋放出來成為Open source的Project，專案的名字我還在想，目前考慮用中文字"川"或是DStreamer之類的名字，如果有任何想法，也歡迎提供給我 :P</p>
<p>除此之外，如果你有玩過GStreamer，應該知道它有一個用指令來播放串流媒體的功能，像這樣子</p>
<blockquote>
<pre class="programlisting">gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink</pre>
</blockquote>
<p>就可以播放ogg的音樂檔案，這只是簡單的例子，它還可以做更複雜的事，例如從麥克風讀取音訊即時壓縮成ogg或mp3格式，且同時播放出來之類的</p>
<p>除了Library，我同樣希望寫出一個像這樣的工具程式，讓某些抓網頁的程式可以被簡化成像這樣的指令，例如</p>
<blockquote><p>dst-launch GetPage url="http://www.google.com" ! RegexParser re="&lt;title&gt;(.*?)&lt;/title&gt;" output="$1&#8243; ! FileOutput filename="google_title.txt"</p></blockquote>
<p>像這樣簡單的指令就能抓取Google網頁的標題然後存成文字檔，除此之外，甚至是GUI介面來像UML那樣設計抓取網頁的流程</p>
<p>有興趣參與或有任何想法都歡迎給個評論，謝謝</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2008/10/11/design-of-web-grabing-program/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>抓取網頁的最佳語言 : Python</title>
		<link>http://blog.ez2learn.com/2008/10/05/python-is-the-best-choice-to-grab-web/</link>
		<comments>http://blog.ez2learn.com/2008/10/05/python-is-the-best-choice-to-grab-web/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 06:51:01 +0000</pubDate>
		<dc:creator>victor</dc:creator>
				<category><![CDATA[中文文章]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[程式設計]]></category>
		<category><![CDATA[抓取網頁]]></category>

		<guid isPermaLink="false">http://blog.ez2learn.com/?p=99</guid>
		<description><![CDATA[最初 最早我用C/C++語言慢慢寫抓網頁的用它來抓網頁真的是程式，一開始甚至打算自己寫抓取網頁的函式庫，想說當做練習，可是HTTP協定 雖然不難，可是煩，要處理的細節太多了，後來受不了，轉而使用現成的Library : cUrl，但是C/C++語言開發這類東西的效率實在太慢了，我的程式不停的修改、不停的修改，光是編譯的時間就吃掉了不知道多少，字串的處理C/C++ 沒有內建正規表示法或一些好用的字串函數之類的，處理起來也礙手礙腳，當時，我想將我寫好的函數庫寫成能讓Lua呼叫的形式，或著甚是C/C++來呼叫Lua，因為C/C++有很多細節要處理，Memory leak有的沒有的雜事，我想要的只是專注在寫抓取網頁的程式，因此用Lua包裝似乎是不錯的選擇，但是開發時間太久了，事情一直沒有變好 直到 我下了一個結論，C/C++不適合寫抓取網頁的程式，我開始思考我需要什麼，我想我既然要包裝成其它語言將細節藏起來，為何不直接使用script語言? 我最早一直擔心的是效率的問題，但是到後來想想反正真正沒效率的部份包給C/C++去做事實上沒有太大的差別，而且又有動態語言的彈性、除錯上的方便等等好處，何樂不為? 於是我開始尋找一款合適的語言 Perl 如何? 很早以前我有用Perl寫過一些CGI程式、留言版、網站管理系統、文章管理系統等等，有人說Perl是只能寫一次的語言，它有很多很簡短的符號所構成的表示法，可讀性不是很好，模組化設計也沒有非常好的支援，OO也是一樣，新版的Perl遲遲沒有推出，似乎已經有點變成遺產的感覺，或許是上面的理由還是偏見，總而言之我不喜歡Perl PHP? 做為一個以網頁為主要用途的語言，拿來當做其它用途總有種不太合適的感覺，從它的語法來看，很明顯是參考C語言、Perl等等而來的，但是卻沒有加以改進，我個人認為它可能沒有預料到PHP居然會紅成這樣，變成網頁程式設計的主流語言，後來有很多缺點就變得顯而易見，不夠嚴僅的語法、不夠好的模組化設計、不良的OO支援、容易寫出安全性有問題的程式等等，命名空間也是它一大缺點之一，光是看到一大堆前綴字開頭的函數就有種倒胃口的感覺，有人說 PHP is the BASIC of the 21st century 在這個影片裡，總合種種理由，做為抓取網頁的用途，PHP出局 Lua Lua做為輕量級的語言相當的優秀，可是你不會想用Lua來寫大型的程式，我也不會想這麼做，它語言的設計都是以速度為優先考量，寫起來並不怎麼順手的感覺，再加上目前的資源不多，可能很多東西都得自行包裝，這樣就和我原先想做的事是一樣的，因此不考慮Lua Java Java是和網路一起成長的程式語言，做為抓取網頁的用途，它絕對有能力勝任，但是&#8230;，我嫌它太囉唆了，還有太癡肥，當一款語言太囉唆和太癡肥往往會令人討厭，歐! 想到Java我就想起eclipse在我那台只有256扣掉分給顯示記憶體的筆電上執行的情況，讓我想把電腦砸掉，不好意思，我不喜歡Java 在前面的影片裡的老兄一樣也有提到，有興趣可以看看 Java is the COBOL of the 21st century Python &#8230; <a href="http://blog.ez2learn.com/2008/10/05/python-is-the-best-choice-to-grab-web/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>最初</h2>
<p>最早我用C/C++語言慢慢寫抓網頁的用它來抓網頁真的是程式，一開始甚至打算自己寫抓取網頁的函式庫，想說當做練習，可是HTTP協定 雖然不難，可是煩，要處理的細節太多了，後來受不了，轉而使用現成的Library : <a href="http://curl.haxx.se/">cUrl</a>，但是C/C++語言開發這類東西的效率實在太慢了，我的程式不停的修改、不停的修改，光是編譯的時間就吃掉了不知道多少，字串的處理C/C++ 沒有內建正規表示法或一些好用的字串函數之類的，處理起來也礙手礙腳，當時，我想將我寫好的函數庫寫成能讓Lua呼叫的形式，或著甚是C/C++來呼叫Lua，因為C/C++有很多細節要處理，Memory leak有的沒有的雜事，我想要的只是專注在寫抓取網頁的程式，因此用Lua包裝似乎是不錯的選擇，但是開發時間太久了，事情一直沒有變好</p>
<h2>直到</h2>
<p><span id="more-99"></span></p>
<p>我下了一個結論，C/C++不適合寫抓取網頁的程式，我開始思考我需要什麼，我想我既然要包裝成其它語言將細節藏起來，為何不直接使用script語言? 我最早一直擔心的是效率的問題，但是到後來想想反正真正沒效率的部份包給C/C++去做事實上沒有太大的差別，而且又有動態語言的彈性、除錯上的方便等等好處，何樂不為? 於是我開始尋找一款合適的語言</p>
<h2>Perl 如何?</h2>
<p>很早以前我有用Perl寫過一些CGI程式、留言版、網站管理系統、文章管理系統等等，有人說Perl是只能寫一次的語言，它有很多很簡短的符號所構成的表示法，可讀性不是很好，模組化設計也沒有非常好的支援，OO也是一樣，新版的Perl遲遲沒有推出，似乎已經有點變成遺產的感覺，或許是上面的理由還是偏見，總而言之我不喜歡Perl</p>
<h2>PHP?</h2>
<p>做為一個以網頁為主要用途的語言，拿來當做其它用途總有種不太合適的感覺，從它的語法來看，很明顯是參考C語言、Perl等等而來的，但是卻沒有加以改進，我個人認為它可能沒有預料到PHP居然會紅成這樣，變成網頁程式設計的主流語言，後來有很多缺點就變得顯而易見，不夠嚴僅的語法、不夠好的模組化設計、不良的OO支援、容易寫出安全性有問題的程式等等，命名空間也是它一大缺點之一，光是看到一大堆前綴字開頭的函數就有種倒胃口的感覺，有人說</p>
<blockquote><p>PHP is the BASIC of the 21st century</p></blockquote>
<p>在這個<a href="http://ia301129.us.archive.org/3/items/SeanKellyRecoveryfromAddiction/Recovery_from_Addiction.mov">影片</a>裡，總合種種理由，做為抓取網頁的用途，PHP出局</p>
<h2><a href="http://www.lua.org/">Lua</a></h2>
<p>Lua做為輕量級的語言相當的優秀，可是你不會想用Lua來寫大型的程式，我也不會想這麼做，它語言的設計都是以速度為優先考量，寫起來並不怎麼順手的感覺，再加上目前的資源不多，可能很多東西都得自行包裝，這樣就和我原先想做的事是一樣的，因此不考慮Lua</p>
<h2>Java</h2>
<p>Java是和網路一起成長的程式語言，做為抓取網頁的用途，它絕對有能力勝任，但是&#8230;，我嫌它太囉唆了，還有太癡肥，當一款語言太囉唆和太癡肥往往會令人討厭，歐! 想到Java我就想起eclipse在我那台只有256扣掉分給顯示記憶體的筆電上執行的情況，讓我想把電腦砸掉，不好意思，我不喜歡Java</p>
<p>在前面的<a href="http://ia301129.us.archive.org/3/items/SeanKellyRecoveryfromAddiction/Recovery_from_Addiction.mov">影片</a>裡的老兄一樣也有提到，有興趣可以看看</p>
<blockquote><p>Java is the COBOL of the 21st century</p></blockquote>
<h2><a href="http://ez2learn.com/python-tutorial/what-is-python">Python</a></h2>
<p>最後，我在PTT的程式設計討論版上描述了我的需求，有人推文說 Python，我抓了抓頭髮，Python? WTF? 這是什麼? 我從來沒有聽過這款語言，於是上網找了一下資料，和問了一些問題，發現這款語言正是我想要的，它很容易被擴充，因此效能不足可以用C/C++補強，你想得到的函式庫幾乎都已經有人寫好了，光從下載網頁這件工作來看，它的標準函式庫已經有了這樣的功能，你覺得不夠好還有其它很多的選擇，開箱即用的哲學，讓安裝函式庫非常簡單，不像C/C++的編譯惡夢讓你抓光頭髮，而它最優秀的地方之一就是它的可讀性，寫起來相當順手、優雅，讀起來也一樣順眼，重要的是很有趣，那麼開發大型的程式呢? script語言常見的問題就是對於開發大型程式來說很不適合，但是Python卻不是如此，良好的OO、模組化等等它都有良好的支援，再加上Google也是Python的愛用者，YouTube也是用Python開發的，有了這些大咖背書，證明這款語言的確是相當優秀，在決定使用Python之後我就立刻訂購了一本<a href="http://www.books.com.tw/exep/assp.php/victorlin/exep/prod/booksfile.php?item=F011223401">Learning Python</a>，開始學習Python</p>
<h2>愛上Python</h2>
<p>Python並沒有讓我失望，能用Python寫的東西都不太想用C/C++去寫，開發效率非常高、寫起來很順手、豐富的資源，讓我覺得這真的是優秀的語言，它的確很適合拿來抓取網頁，不過抓取網頁還有更多東西要考慮</p>
<h2><a href="http://ez2learn.com/python-tutorial/third-party/twisted-tutorial/what-is-twisted">Twisted</a></h2>
<p>用Python抓取網頁的HTML只是小菜一盤，用Python標準函數庫就辦得到，但不是那麼好用，最後我發現了Twisted，就改用Twisted來抓網頁，它有優秀的非同步事件驅動的架構，常見的協定都已經有實做，包括HTTP、SMTP等等，用它來抓網頁真的是再容易不過了</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">getPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.google.com&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>printPage<span style="color: black;">&#41;</span></pre></div></div>

<p>是的，一行就可以抓網頁，夠簡單吧，而且你想要傳POST或GET等參數，或是修改HTTP的header都沒有問題</p>
<h2><a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a></h2>
<p>抓網頁事實上不是什麼難事，解析HTML要來得更麻煩，最初使用Python的標準函式庫內建的HTMLParser來解析網頁，但是功能太陽春，加上最頭痛的問題是，大部份的網頁都沒有完全尊照標準來寫，各種莫明奇妙的錯誤令人想要找出那個寫網頁的人痛打他一頓，為了解決容錯的問題，一開始我使用BeautifulSoup來抓取網頁，它是以容錯著名的HTML Parser，但是，它的效率很差，又或著說，找到目標HTML標籤的方式很沒效率，一般都用find等方式來找到所要的標籤</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">soup.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'div'</span>, <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: #008000;">id</span>=<span style="color: #483d8b;">'content'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>它真的很沒效率，當你抓取大一點的網頁時，多塞幾個一起抓和解析，你就會看見你的CPU使用率永遠是滿的狀態，原本我預計抓網頁的瓶頸都會落在網路IO上面，但是用它來抓取網頁卻超出我預料，沒想到它會這麼吃重，於是沒辦法，我開始尋找更好的選擇</p>
<h2><a href="http://codespeak.net/lxml/">lxml</a></h2>
<p>我找到一個Blog的文章 : <a href="http://blog.ianbicking.org/2008/03/30/python-html-parser-performance/">Python HTML Parser Performance</a>，介紹了Python各種Parser的效能，效能最亮眼的，就是lxml，我最初擔心的是找到資料標籤會不會很困難，但是我發現它支援xpath，就試著改寫原本BeautifulSoup用find等等函數寫的尋找標籤程式，發現xpath遠比那種方式來得好用太多了，而且效率好太多了，BeautifulSoup的find極度的沒有效率，大部份的CPU時間都耗在一堆find函數走訪HTML樹上，而xpath篩選標籤的方式來得有效率多了，以下舉幾個我實際用在抓取網頁的案子中的例子</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> getNextPageLink<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, tree<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Get next page link
&nbsp;
    @param tree: tree to get link
    @return: Return url of next page, if there is no next page, return None
    &quot;&quot;&quot;</span>
    paging = tree.<span style="color: black;">xpath</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;//span[@class='paging']&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> paging:
        links = paging<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">xpath</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;./a[(text(), '%s')]&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">localText</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'next'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> links:
            <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>links<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'href'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">listPrice = tree.<span style="color: black;">xpath</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;//*[@class='priceBlockLabel']/following-sibling::*&quot;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">if</span> listPrice:
    detail<span style="color: black;">&#91;</span><span style="color: #483d8b;">'listPrice'</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">stripMoney</span><span style="color: black;">&#40;</span>listPrice<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">text</span><span style="color: black;">&#41;</span></pre></div></div>

<p>原本使用BeautifulSoup在尋找標籤遇到麻煩的走訪羅輯上的問題還得寫程式解決，xpath本身就有豐富的語法可以提供各種篩選的條件，羅輯從程式碼被移到了xpath語法上，有了這樣的語法，尋找目標標籤輕鬆了許多，而且效率也很好，從此我就和BeautifulSoup說再見，改用lxml來找標籤</p>
<h2>配合FireFox的工具</h2>
<p>如果有一些工具可以幫助寫解析網頁的程式該有多好，這也是我希望能有的，使用了xpath之後，我找到了FireFox的插件，XPath checker等xpath的工具，可以先用它來確定抓到的元素是正確的，然後FireBug在檢視網頁結構上也有很大的幫助</p>
<div id="attachment_110" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/2008-10-05_142302.png"><img class="size-medium wp-image-110" title="FireFox插件XPath checker畫面" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/2008-10-05_142302-300x238.png" alt="FireFox插件XPath checker畫面" width="300" height="238" /></a><p class="wp-caption-text">FireFox插件XPath checker畫面</p></div>
<div id="attachment_111" class="wp-caption alignnone" style="width: 310px"><a href="http://blog.ez2learn.com/wp-content/uploads/2008/10/2008-10-05_142402.png"><img class="size-medium wp-image-111" title="使用FireBug檢視網頁元素" src="http://blog.ez2learn.com/wp-content/uploads/2008/10/2008-10-05_142402-300x176.png" alt="使用FireBug檢視網頁元素" width="300" height="176" /></a><p class="wp-caption-text">使用FireBug檢視網頁元素</p></div>
<h2>結論</h2>
<p>就目前一路走過來的經驗來看，抓取網頁Python的確是最佳的選擇，不過我們到目前為止我們都只討論到工具，事實上還有設計上的問題要解決，留在下一次寫</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ez2learn.com/2008/10/05/python-is-the-best-choice-to-grab-web/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
<enclosure url="http://ia301129.us.archive.org/3/items/SeanKellyRecoveryfromAddiction/Recovery_from_Addiction.mov" length="18263101" type="video/quicktime" />
		</item>
	</channel>
</rss>

