Ⅰ 為什麼c語言不適合寫爬蟲
c語言不適合寫爬蟲是因為,C語言本質上是需要發請求加html解析的,所以可用的開源庫相比較於Python來說就會少很多,如果不使用開源庫而自己發請求,加上自己來解析,那就是一個特別浩瀚龐大的工程,因此最好不要用c語言來寫爬蟲。這里所說的爬蟲,其實原理了來說就是發送HTTP請求加上解析html頁面,從而能夠獲取頁面上的一些目標數據。任何的一個編程語言理論上來說都是能夠寫爬蟲的,不過寫起來可用的庫或者是難易程度方面是有很大的差異的,用python可以使用別人已經封裝好的爬蟲框架,這樣就便捷多了。
C語言和 Python 是編程語言界的兩個極端,從不同的語言入手學習,就是選擇了兩條不同的學習路徑。C語言執行效率極高,堪比匯編語言;Python 執行效率極低,而且沒法提速。Python 模塊非常豐富,大部分常用功能都可以找到對應的模塊,而且很有可能不止一個;C語言基本沒有什麼模塊,想要什麼都得自己開發,或者把別人寫好的代碼拿過來改改。
Ⅱ python為什麼叫爬蟲
因為python的腳本特性,易於配置,對字元的處理也非常靈活,就像蟲子一樣靈活,故名爬蟲。
Python是完全面向對象的語言。函數、模塊、數字、字元串都是對象。並且完全支持繼承、重載、派生、多繼承,有益於增強源代碼的復用性。
Python支持重載運算符和動態類型。相對於Lisp這種傳統的函數式編程語言,Python對函數式設計只提供了有限的支持。有兩個標准庫(functools, itertools)提供了Haskell和Standard ML中久經考驗的函數式程序設計工具。
擴展資料
Python的設計目標之一是讓代碼具備高度的可閱讀性。它設計時盡量使用其它語言經常使用的標點符號和英文單字,讓代碼看起來整潔美觀。它不像其他的靜態語言如C、Pascal那樣需要重復書寫聲明語句,也不像它們的語法那樣經常有特殊情況和意外。
Python開發者有意讓違反了縮進規則的程序不能通過編譯,以此來強製程序員養成良好的編程習慣。
並且Python語言利用縮進表示語句塊的開始和退出(Off-side規則),而非使用花括弧或者某種關鍵字。增加縮進表示語句塊的開始,而減少縮進則表示語句塊的退出。縮進成為了語法的一部分。
例如if語句:python3。
Ⅲ C#爬蟲爬蟲的多線程如何實現
開發網路爬蟲應該選擇Nutch、Crawler4j、WebMagic、scrapy、WebCollector還是其他的?這里按照我的經驗隨便扯淡一下:上面說的爬蟲,基本可以分3類:1.分布式爬蟲:Nutch
2.JAVA單機爬蟲:Crawler4j、WebMagic、WebCollector
3. 非JAVA單機爬蟲:scrapy
第一類:分布式爬蟲
爬蟲使用分布式,主要是解決兩個問題:
1)海量URL管理
2)網速
現在比較流行的分布式爬蟲,是Apache的Nutch。但是對於大多數用戶來說,Nutch是這幾類爬蟲里,最不好的選擇,理由如下:
1)Nutch是為搜索引擎設計的爬蟲,大多數用戶是需要一個做精準數據爬取(精抽取)的爬蟲。Nutch運行的一套流程里,有三分之二是為了搜索引擎而設計的。對精抽取沒有太大的意義。也就是說,用Nutch做數據抽取,會浪費很多的時間在不必要的計算上。而且如果你試圖通過對Nutch進行二次開發,來使得它適用於精抽取的業務,基本上就要破壞Nutch的框架,把Nutch改的面目全非,有修改Nutch的能力,真的不如自己重新寫一個分布式爬蟲框架了。
2)Nutch依賴hadoop運行,hadoop本身會消耗很多的時間。如果集群機器數量較少,爬取速度反而不如單機爬蟲快。
3)Nutch雖然有一套插件機制,而且作為亮點宣傳。可以看到一些開源的Nutch插件,提供精抽取的功能。但是開發過Nutch插件的人都知道,Nutch的插件系統有多蹩腳。利用反射的機制來載入和調用插件,使得程序的編寫和調試都變得異常困難,更別說在上面開發一套復雜的精抽取系統了。而且Nutch並沒有為精抽取提供相應的插件掛載點。Nutch的插件有隻有五六個掛載點,而這五六個掛載點都是為了搜索引擎服務的,並沒有為精抽取提供掛載點。大多數Nutch的精抽取插件,都是掛載在「頁面解析」(parser)這個掛載點的,這個掛載點其實是為了解析鏈接(為後續爬取提供URL),以及為搜索引擎提供一些易抽取的網頁信息(網頁的meta信息、text文本)。
4)用Nutch進行爬蟲的二次開發,爬蟲的編寫和調試所需的時間,往往是單機爬蟲所需的十倍時間不止。了解Nutch源碼的學習成本很高,何況是要讓一個團隊的人都讀懂Nutch源碼。調試過程中會出現除程序本身之外的各種問題(hadoop的問題、hbase的問題)。
5)很多人說Nutch2有gora,可以持久化數據到avro文件、hbase、mysql等。很多人其實理解錯了,這里說的持久化數據,是指將URL信息(URL管理所需要的數據)存放到avro、hbase、mysql。並不是你要抽取的結構化數據。其實對大多數人來說,URL信息存在哪裡無所謂。
6)Nutch2的版本目前並不適合開發。官方現在穩定的Nutch版本是nutch2.2.1,但是這個版本綁定了gora-0.3。如果想用hbase配合nutch(大多數人用nutch2就是為了用hbase),只能使用0.90版本左右的hbase,相應的就要將hadoop版本降到hadoop 0.2左右。而且nutch2的官方教程比較有誤導作用,Nutch2的教程有兩個,分別是Nutch1.x和Nutch2.x,這個Nutch2.x官網上寫的是可以支持到hbase 0.94。但是實際上,這個Nutch2.x的意思是Nutch2.3之前、Nutch2.2.1之後的一個版本,這個版本在官方的SVN中不斷更新。而且非常不穩定(一直在修改)。
所以,如果你不是要做搜索引擎,盡量不要選擇Nutch作為爬蟲。有些團隊就喜歡跟風,非要選擇Nutch來開發精抽取的爬蟲,其實是沖著Nutch的名氣(Nutch作者是Doug Cutting),當然最後的結果往往是項目延期完成。
如果你是要做搜索引擎,Nutch1.x是一個非常好的選擇。Nutch1.x和solr或者es配合,就可以構成一套非常強大的搜索引擎了。如果非要用Nutch2的話,建議等到Nutch2.3發布再看。目前的Nutch2是一個非常不穩定的版本。
第二類:JAVA單機爬蟲
這里把JAVA爬蟲單獨分為一類,是因為JAVA在網路爬蟲這塊的生態圈是非常完善的。相關的資料也是最全的。這里可能有爭議,我只是隨便扯淡。
其實開源網路爬蟲(框架)的開發非常簡單,難問題和復雜的問題都被以前的人解決了(比如DOM樹解析和定位、字元集檢測、海量URL去重),可以說是毫無技術含量。包括Nutch,其實Nutch的技術難點是開發hadoop,本身代碼非常簡單。網路爬蟲從某種意義來說,類似遍歷本機的文件,查找文件中的信息。沒有任何難度可言。之所以選擇開源爬蟲框架,就是為了省事。比如爬蟲的URL管理、線程池之類的模塊,誰都能做,但是要做穩定也是需要一段時間的調試和修改的。
對於爬蟲的功能來說。用戶比較關心的問題往往是:
1)爬蟲支持多線程么、爬蟲能用代理么、爬蟲會爬取重復數據么、爬蟲能爬取JS生成的信息么?
不支持多線程、不支持代理、不能過濾重復URL的,那都不叫開源爬蟲,那叫循環執行http請求。
能不能爬js生成的信息和爬蟲本身沒有太大關系。爬蟲主要是負責遍歷網站和下載頁面。爬js生成的信息和網頁信息抽取模塊有關,往往需要通過模擬瀏覽器(htmlunit,selenium)來完成。這些模擬瀏覽器,往往需要耗費很多的時間來處理一個頁面。所以一種策略就是,使用這些爬蟲來遍歷網站,遇到需要解析的頁面,就將網頁的相關信息提交給模擬瀏覽器,來完成JS生成信息的抽取。
2)爬蟲可以爬取ajax信息么?
網頁上有一些非同步載入的數據,爬取這些數據有兩種方法:使用模擬瀏覽器(問題1中描述過了),或者分析ajax的http請求,自己生成ajax請求的url,獲取返回的數據。如果是自己生成ajax請求,使用開源爬蟲的意義在哪裡?其實是要用開源爬蟲的線程池和URL管理功能(比如斷點爬取)。
如果我已經可以生成我所需要的ajax請求(列表),如何用這些爬蟲來對這些請求進行爬取?
爬蟲往往都是設計成廣度遍歷或者深度遍歷的模式,去遍歷靜態或者動態頁面。爬取ajax信息屬於deep web(深網)的范疇,雖然大多數爬蟲都不直接支持。但是也可以通過一些方法來完成。比如WebCollector使用廣度遍歷來遍歷網站。爬蟲的第一輪爬取就是爬取種子集合(seeds)中的所有url。簡單來說,就是將生成的ajax請求作為種子,放入爬蟲。用爬蟲對這些種子,進行深度為1的廣度遍歷(默認就是廣度遍歷)。
3)爬蟲怎麼爬取要登陸的網站?
這些開源爬蟲都支持在爬取時指定cookies,模擬登陸主要是靠cookies。至於cookies怎麼獲取,不是爬蟲管的事情。你可以手動獲取、用http請求模擬登陸或者用模擬瀏覽器自動登陸獲取cookie。
4)爬蟲怎麼抽取網頁的信息?
開源爬蟲一般都會集成網頁抽取工具。主要支持兩種規范:CSS SELECTOR和XPATH。至於哪個好,這里不評價。
5)爬蟲怎麼保存網頁的信息?
有一些爬蟲,自帶一個模塊負責持久化。比如webmagic,有一個模塊叫pipeline。通過簡單地配置,可以將爬蟲抽取到的信息,持久化到文件、資料庫等。還有一些爬蟲,並沒有直接給用戶提供數據持久化的模塊。比如crawler4j和webcollector。讓用戶自己在網頁處理模塊中添加提交資料庫的操作。至於使用pipeline這種模塊好不好,就和操作資料庫使用ORM好不好這個問題類似,取決於你的業務。
6)爬蟲被網站封了怎麼辦?
爬蟲被網站封了,一般用多代理(隨機代理)就可以解決。但是這些開源爬蟲一般沒有直接支持隨機代理的切換。所以用戶往往都需要自己將獲取的代理,放到一個全局數組中,自己寫一個代理隨機獲取(從數組中)的代碼。
7)網頁可以調用爬蟲么?
爬蟲的調用是在Web的服務端調用的,平時怎麼用就怎麼用,這些爬蟲都可以使用。
8)爬蟲速度怎麼樣?
單機開源爬蟲的速度,基本都可以講本機的網速用到極限。爬蟲的速度慢,往往是因為用戶把線程數開少了、網速慢,或者在數據持久化時,和資料庫的交互速度慢。而這些東西,往往都是用戶的機器和二次開發的代碼決定的。這些開源爬蟲的速度,都很可以。
9)明明代碼寫對了,爬不到數據,是不是爬蟲有問題,換個爬蟲能解決么?
如果代碼寫對了,又爬不到數據,換其他爬蟲也是一樣爬不到。遇到這種情況,要麼是網站把你封了,要麼是你爬的數據是javascript生成的。爬不到數據通過換爬蟲是不能解決的。
10)哪個爬蟲可以判斷網站是否爬完、那個爬蟲可以根據主題進行爬取?
爬蟲無法判斷網站是否爬完,只能盡可能覆蓋。
至於根據主題爬取,爬蟲之後把內容爬下來才知道是什麼主題。所以一般都是整個爬下來,然後再去篩選內容。如果嫌爬的太泛,可以通過限制URL正則等方式,來縮小一下范圍。
11)哪個爬蟲的設計模式和構架比較好?
設計模式純屬扯淡。說軟體設計模式好的,都是軟體開發完,然後總結出幾個設計模式。設計模式對軟體開發沒有指導性作用。用設計模式來設計爬蟲,只會使得爬蟲的設計更加臃腫。
至於構架,開源爬蟲目前主要是細節的數據結構的設計,比如爬取線程池、任務隊列,這些大家都能控制好。爬蟲的業務太簡單,談不上什麼構架。
所以對於JAVA開源爬蟲,我覺得,隨便找一個用的順手的就可以。如果業務復雜,拿哪個爬蟲來,都是要經過復雜的二次開發,才可以滿足需求。
第三類:非JAVA單機爬蟲
在非JAVA語言編寫的爬蟲中,有很多優秀的爬蟲。這里單獨提取出來作為一類,並不是針對爬蟲本身的質量進行討論,而是針對larbin、scrapy這類爬蟲,對開發成本的影響。
先說python爬蟲,python可以用30行代碼,完成JAVA 50行代碼乾的任務。python寫代碼的確快,但是在調試代碼的階段,python代碼的調試往往會耗費遠遠多於編碼階段省下的時間。使用python開發,要保證程序的正確性和穩定性,就需要寫更多的測試模塊。當然如果爬取規模不大、爬取業務不復雜,使用scrapy這種爬蟲也是蠻不錯的,可以輕松完成爬取任務。
對於C++爬蟲來說,學習成本會比較大。而且不能只計算一個人的學習成本,如果軟體需要團隊開發或者交接,那就是很多人的學習成本了。軟體的調試也不是那麼容易。
還有一些ruby、php的爬蟲,這里不多評價。的確有一些非常小型的數據採集任務,用ruby或者php很方便。但是選擇這些語言的開源爬蟲,一方面要調研一下相關的生態圈,還有就是,這些開源爬蟲可能會出一些你搜不到的BUG(用的人少、資料也少)
Ⅳ 我想學習網路爬蟲,哪位高手能給我發代碼java、c#、C++都可以,先謝謝了。郵箱:[email protected]
C#特別適合於構造蜘蛛程序,這是因為它已經內置了HTTP和多線程的能力,而這兩種能力對於蜘蛛程序來說都是非常關鍵的。下面是構造一個蜘蛛程序要解決的關鍵問題:⑴ HTML分析:需要某種HTML解析器來分析蜘蛛程序遇到的每一個頁面。
⑵ 頁面處理:需要處理每一個下載得到的頁面。下載得到的內容可能要保存到磁碟,或者進一步分析處理。
⑶ 多線程:只有擁有多線程能力,蜘蛛程序才能真正做到高效。
⑷ 確定何時完成:不要小看這個問題,確定任務是否已經完成並不簡單,尤其是在多線程環境下。
一、HTML解析
提供的HTML解析器由ParseHTML類實現,使用非常方便:首先創建該類的一個實例,然後將它的Source屬性設置為要解析的HTML文檔:
以下是代碼片段:
ParseHTMLparse=newParseHTML();
parse.Source="HelloWorld";
接下來就可以利用循環來檢查HTML文檔包含的所有文本和標記。通常,檢查過程可以從一個測試Eof方法的while循環開始:
以下是代碼片段:
while(!parse.Eof())
{
charch=parse.Parse();
Parse方法將返回HTML文檔包含的字元它返回的內容只包含那些非HTML標記的字元,如果遇到了HTML標記,Parse方法將返回0值,表示現在遇到了一個HTML標記。遇到一個標記之後,我們可以用GetTag()方法來處理它。
以下是代碼片段:
if(ch==0)
{
HTMLTagtag=parse.GetTag();
}
一般地,蜘蛛程序最重要的任務之一就是找出各個HREF屬性,這可以藉助C#的索引功能完成。例如,下面的代碼將提取出HREF屬性的值(如果存在的話)。
以下是代碼片段:
Attributehref=tag["HREF"];
stringlink=href.Value;
獲得Attribute對象之後,通過Attribute.Value可以得到該屬性的值。
二、處理HTML頁面
下面來看看如何處理HTML頁面。首先要做的當然是下載HTML頁面,這可以通過C#提供的HttpWebRequest類實現:
以下是代碼片段:
HttpWebRequestrequest=(HttpWebRequest)WebRequest.Create(m_uri);
response=request.GetResponse();
stream=response.GetResponseStream();
接下來我們就從request創建一個stream流。在執行其他處理之前,我們要先確定該文件是二進制文件還是文本文件,不同的文件類型處理方式也不同。下面的代碼確定該文件是否為二進制文件。
以下是代碼片段:
if(!response.ContentType.ToLower().StartsWith("text/"))
{
SaveBinaryFile(response);
returnnull;
}
stringbuffer="",line;
如果該文件不是文本文件,我們將它作為二進制文件讀入。如果是文本文件,首先從stream創建一個StreamReader,然後將文本文件的內容一行一行加入緩沖區。
以下是代碼片段:
reader=newStreamReader(stream);
while((line=reader.ReadLine())!=null)
{
buffer+=line+"rn";
}
裝入整個文件之後,接著就要把它保存為文本文件。
以下是代碼片段:
SaveTextFile(buffer);
下面來看看這兩類不同文件的存儲方式。
二進制文件的內容類型聲明不以"text/"開頭,蜘蛛程序直接把二進制文件保存到磁碟,不必進行額外的處理,這是因為二進制文件不包含HTML,因此也不會再有需要蜘蛛程序處理的HTML。下面是寫入二進制文件的步驟。
首先准備一個緩沖區臨時地保存二進制文件的內容。
以下是代碼片段:
byte[]buffer=newbyte[1024];
接下來要確定文件保存到本地的路徑和名稱。如果要把一個myhost.com網站的內容下載到本地的c:test文件夾,二進制文件的網上路徑和名稱是,則本地路徑和名稱應當是c:testimageslogo.gif。與此同時,我們還要確保c:test目錄下已經創建了images子目錄。這部分任務由convertFilename方法完成。
以下是代碼片段:
stringfilename=convertFilename(response.ResponseUri);
convertFilename方法分離HTTP地址,創建相應的目錄結構。確定了輸出文件的名字和路徑之後就可以打開讀取Web頁面的輸入流、寫入本地文件的輸出流。
以下是代碼片段:
StreamoutStream=File.Create(filename);
StreaminStream=response.GetResponseStream();
接下來就可以讀取Web文件的內容並寫入到本地文件,這可以通過一個循環方便地完成。
以下是代碼片段:
intl;
do
{
l=inStream.Read(buffer,0,
buffer.Length);
if(l>0)
outStream.Write(buffer,0,l);
}
while(l>0);
三、多線程
我們用DocumentWorker類封裝所有下載一個URL的操作。每當一個DocumentWorker的實例被創建,它就進入循環,等待下一個要處理的URL。下面是DocumentWorker的主循環:
以下是代碼片段:
while(!m_spider.Quit)
{
m_uri=m_spider.ObtainWork();
m_spider.SpiderDone.WorkerBegin();
stringpage=GetPage();
if(page!=null)
ProcessPage(page);
m_spider.SpiderDone.WorkerEnd();
}
這個循環將一直運行,直至Quit標記被設置成了true(當用戶"Cancel"按鈕時,Quit標記就被設置成true)。在循環之內,我們調用ObtainWork獲取一個URL。ObtainWork將一直等待,直到有一個URL可用這要由其他線程解析文檔並尋找才能獲得。Done類利用WorkerBegin和WorkerEnd方法來確定何時整個下載操作已經完成。
從圖一可以看出,蜘蛛程序允許用戶自己確定要使用的線程數量。在實踐中,線程的最佳數量受許多因素影響。如果你的機器性能較高,或者有兩個處理器,可以設置較多的線程數量;反之,如果網路帶寬、機器性能有限,設置太多的線程數量其實不一定能夠提高性能。
四、任務完成了嗎?
利用多個線程同時下載文件有效地提高了性能,但也帶來了線程管理方面的問題。其中最復雜的一個問題是:蜘蛛程序何時才算完成了工作?在這里我們要藉助一個專用的類Done來判斷。
首先有必要說明一下"完成工作"的具體含義。只有當系統中不存在等待下載的URL,而且所有工作線程都已經結束其處理工作時,蜘蛛程序的工作才算完成。也就是說,完成工作意味著已經沒有等待下載和正在下載的URL。
Done類提供了一個WaitDone方法,它的功能是一直等待,直到Done對象檢測到蜘蛛程序已完成工作。下面是WaitDone方法的代碼。
以下是代碼片段:
publicvoidWaitDone()
{
Monitor.Enter(this);
while(m_activeThreads>0)
{
Monitor.Wait(this);
}
Monitor.Exit(this);
}
WaitDone方法將一直等待,直到不再有活動的線程。但必須注意的是,下載開始的最初階段也沒有任何活動的線程,所以很容易造成蜘蛛程序一開始就立即停止的現象。為解決這個問題,我們還需要另一個方法WaitBegin來等待蜘蛛程序進入"正式的"工作階段。一般的調用次序是:先調用WaitBegin,再接著調用WaitDone,WaitDone將等待蜘蛛程序完成工作。下面是WaitBegin的代碼:
以下是代碼片段:
publicvoidWaitBegin()
{
Monitor.Enter(this);
while(!m_started)
{
Monitor.Wait(this);
}
Monitor.Exit(this);
【引自Felomeng的博客】在《爬蟲/蜘蛛程序的製作(C#語言)》一文中,已經介紹了爬蟲程序實現的基本方法,可以說,已經實現了爬蟲的功能。只是它存在一個效率問題,下載速度可能很慢。這是兩方面的原因造成的:
1.分析和下載不能同步進行。在《爬蟲/蜘蛛程序的製作(C#語言)》中已經介紹了爬蟲程序的兩個步驟:分析和下載。在單線程的程序中,兩者是無法 同時進行的。也就是說,分析時會造成網路空閑,分析的時間越長,下載的效率越低。反之也是一樣,下載時無法同時進行分析,只有停下下載後才能進行下一步的 分析。問題浮出水面,我想大家都會想到:把分析和下載用不同的線程進行,問題不就解決了嗎?
2.只是單線程下載。相信大家都有用過網際快車等下載資源的經歷,它裡面是可以設置線程數的(近年版本默認是10,曾經默認是5)。它會將文件分成 與線程數相同的部分,然後每個線程下載自己的那一部分,這樣下載效率就有可能提高。相信大家都有加多線程數,提升下載效率的經歷。但細心的用戶會發現,在 帶寬一定的情況下,並不是線程越多,速度越快,而是在某一點達到峰值。爬蟲作為特殊的下載工具,不具備多線程的能力何以有效率可談?爬蟲在信息時代的目 的,難道不是快速獲取信息嗎?所以,爬蟲需要有多線程(可控數量)同時下載網頁。
好了,認識、分析完問題,就是解決問題了:
多線程在C#中並不難實現。它有一個命名空間:System.Threading,提供了多線程的支持。
要開啟一個新線程,需要以下的初始化:
ThreadStart startDownload = new ThreadStart( DownLoad );
//線程起始設置:即每個線程都執行DownLoad(),注意:DownLoad()必須為不帶有參數的方法
Thread downloadThread = new Thread( startDownload ); //實例化要開啟的新類
downloadThread.Start();//開啟線程
由於線程起始時啟動的方法不能帶有參數,這就為多線程共享資源添加了麻煩。不過我們可以用類級變數(當然也可以使用其它方法,筆者認為此方法最簡單易用)來解決這個問題。知道開啟多線程下載的方法後,大家可能會產生幾個疑問:
1.如何控制線程的數量?
2.如何防止多線程下載同一網頁?
3.如何判斷線程結束?
4.如何控制線程結束?
下面就這幾個問題提出解決方法:
1.線程數量我們可以通過for循環來實現,就如同當年初學編程的打點程序一樣。
比如已知用戶指定了n(它是一個int型變數)個線程吧,可以用如下方法開啟五個線程。
Thread[] downloadThread;
//聲名下載線程,這是C#的優勢,即數組初始化時,不需要指定其長度,可以在使用時才指定。
這個聲名應為類級,這樣也就為其它方法控制項它們提供了可能
ThreadStart startDownload = new ThreadStart( DownLoad );
//線程起始設置:即每個線程都執行DownLoad()
downloadThread = new Thread[ n ];//為線程申請資源,確定線程總數
for( int i = 0; i < n; i++ )//開啟指定數量的線程數
{
downloadThread[i] = new Thread( startDownload );//指定線程起始設置
downloadThread[i].Start();//逐個開啟線程
}
好了,實現控制開啟線程數是不是很簡單啊?
2.下面出現的一個問題:所有的線程都調用DonwLoad()方法,這樣如何避免它們同時下載同一個網頁呢?
這個問題也好解決,只要建立一下Url地址表,表中的每個地址只允許被一個線程申請即可。具體實現:
可以利用資料庫,建立一個表,表中有四列,其中一列專門用於存儲Url地址,另外兩列分別存放地址對應的線程以及該地址被申請的次數,最後一列存放 下載的內容。(當然,對應線程一列不是必要的)。當有線程申請後,將對應線程一列設定為當前線程編號,並將是否申請過一列設置為申請一次,這樣,別的線程 就無法申請該頁。如果下載成功,則將內容存入內容列。如果不成功,內容列仍為空,作為是否再次下載的依據之一,如果反復不成功,則進程將於達到重試次數 (對應該地址被申請的次數,用戶可設)後,申請下一個Url地址。主要的代碼如下(以VFP為例):
<建立表>
CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I )
&&建立一個表ctablename.dbf,含有地址、文本內容、已經嘗試下載次數、
線程標志(初值為-1,線程標志是從0開始的整數)四個欄位
<提取Url地址>
cfullname = (ctablename) + '.dbf'&&為表添加擴展名
USE (cfullname)
GO TOP
LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND
( threadNum = thisNum OR threadNum = - 1) )
&&查找尚未下載成功且應下載的屬於本線程許可權的Url地址,thisNum是當前線程的編號,
可以通過參數傳遞得到
gotUrl = curl
recNum = RECNO()
IF recNum <= RECCOUNT() THEN &&如果在列表中找到這樣的Url地址
UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum =
thisNum WHERE RECNO() = recNum &&更新表,將此記錄更新為已申請,即下載次數加1,
線程標志列設為本線程的編號。
<下載內容>
cfulltablename = (ctablename) + '.dbf'
USE (cfulltablename)
SET EXACT ON
LOCATE FOR curl = (csiteurl) && csiteurl是參數,為下載到的內容所對應的Url地址
recNumNow = RECNO()&&得到含有此地址的記錄號
UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() =
recNumNow &&插入對應地址的對應內容
<插入新地址>
ctablename = (ctablename) + '.dbf'
USE (ctablename)
GO TOP
SET EXACT ON
LOCATE FOR curl = (cnewurl) &&查找有無此地址
IF RECNO() > RECCOUNT() THEN &&如果尚無此地址
SET CARRY OFF
INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum )
VALUES ( (cnewurl) , "" , 0 , -1 ) &&將主頁地址添加到列表
好了,這樣就解決了多線程中,線程沖突。當然,去重問題也可以在C#語言內解決,只根建立一個臨時文件(文本就可以),保存所有的Url地址,差對它們設置相應的屬性即可,但查找效率可能不及資料庫快。
共2頁
3.線程結束是很難判斷的,因為它總是在查找新的鏈接。用者認為可以假設:線程重復N次以後還是沒有能申請到新的Url地址,那麼可以認為它已經下載完了所有鏈接。主要代碼如下:
string url = "";
int times = 0;
while ( url == "" )//如果沒有找到符合條件的記錄,則不斷地尋找符合條件的記錄
{
url = getUrl.GetAUrl( …… );//調用GetAUrl方法,試圖得到一個url值
if ( url == "" )//如果沒有找到
{
times ++;//嘗試次數自增
continue; //進行下一次嘗試
}
if ( times > N ) //如果已經嘗試夠了次數,則退出進程
{
downloadThread[i].Abort; //退出進程
}
else//如果沒有嘗試夠次數
{
Times = 0; //嘗試次數歸零處理
}
//進行下一步針對得到的Url的處理
}
4.這個問題相對簡單,因為在問題一中已經建議,將線程聲名為類級數組,這樣就很易於控制。只要用一個for循環即可結束。代碼如下:
for( int i = 0; i < n; i++ )//關閉指定數量n的線程數
{
downloadThread[i].Abort();//逐個關閉線程
}
好了,一個蜘蛛程序就這樣完成了,在C#面前,它的實現原來如此簡單。
這里筆者還想提醒讀者:筆者只是提供了一個思路及一個可以實現的解決方案,但它並不是最佳的,即使這個方案本身,也有好多可以改進的地方,留給讀者思考。
最後說明一下我所使用的環境:
winXP sp2 Pro
VFP 9.0
Visual Studio 2003 .net中文企業版
Ⅳ 如何優雅地使用c語言編寫爬蟲
大家在平時或多或少地都會有編寫網路爬蟲的需求。一般來說,編寫爬蟲的首選自然非python莫屬,除此之外,java等語言也是不錯的選擇。選擇上述語言的原因不僅僅在於它們均有非常不錯的網路請求庫和字元串處理庫,還在於基於上述語言的爬蟲框架非常之多和完善。良好的爬蟲框架可以確保爬蟲程序的穩定性,以及編寫程序的便捷性。所以,這個cspider爬蟲庫的使命在於,我們能夠使用c語言,依然能夠優雅地編寫爬蟲程序。
爬蟲的特性
配置方便。使用一句設置函數,即可定義user agent,cookie,timeout,proxy以及抓取線程和解析線程的最大數量。
程序邏輯獨立。用戶可以分別定義爬蟲的解析函數,和數據持久化函數。並且對於解析到的新url,用戶可以使用cspider提供的addUrl函數,將其加入到任務隊列中。
便捷的字元串處理。cspider中提供了基於pcre的簡單的正則表達式函數,基於libxml2的xpath解析函數,以及用於解析json的cJSON庫。
高效的抓取。cspider基於libuv調度抓取線程和解析線程,使用curl作為其網路請求庫。
使用cspider的步驟
獲取cspider_t。
自定義user agent,cookie,timeout,proxy以及抓取線程和解析線程的最大數量。
添加初始要抓取的url到任務隊列。
編寫解析函數和數據持久化函數。
啟動爬蟲。
例子
先來看下簡單的爬蟲例子,會在後面詳細講解例子。
#include<cspider/spider.h>
/*
自定義的解析函數,d為獲取到的html頁面字元串
*/
void p(cspider_t *cspider, char *d, void *user_data) {
char *get[100];
//xpath解析html
int size = xpath(d, "//body/div[@class='wrap']/div[@class='sort-column area']/div[@class='column-bd cfix']/ul[@class='st-list cfix']/li/strong/a", get, 100);
int i;
for (i = 0; i < size; i++) {
//將獲取到的電影名稱,持久化
saveString(cspider, get[i]);
}
}
/*
數據持久化函數,對上面解析函數中調用的saveString()函數傳入的數據,進行進一步的保存
*/
void s(void *str, void *user_data) {
char *get = (char *)str;
FILE *file = (FILE*)user_data;
fprintf(file, "%s\n", get);
return;
}
int main() {
//初始化spider
cspider_t *spider = init_cspider();
char *agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0";
//char *cookie = "bid=s3/yuH5Jd/I; ll=108288; viewed=1130500_24708145_6433169_4843567_1767120_5318823_1899158_1271597; __utma=30149280.927537245.1446813674.1446983217.1449139583.4; __utmz=30149280.1449139583.4.4.utmcsr=accounts.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/login; ps=y; [email protected]; dbcl2=58742090:QgZ2PSLiDLQ; ck=T9Wn; push_noty_num=0; push_doumail_num=7; ap=1; __utmb=30149280.0.10.1449139583; __utmc=30149280";
//設置要抓取頁面的url
cs_setopt_url(spider, "so.tv.sohu.com/list_p1100_p20_p3_u5185_u5730_p40_p5_p6_p77_p80_p9_2d1_p101_p11.html");
//設置user agent
cs_setopt_useragent(spider, agent);
//cs_setopt_cookie(spider, cookie);
//傳入解析函數和數據持久化函數的指針
cs_setopt_process(spider, p, NULL);
//s函數的user_data指針指向stdout
cs_setopt_save(spider, s, stdout);
//設置線程數量
cs_setopt_threadnum(spider, DOWNLOAD, 2);
cs_setopt_threadnum(spider, SAVE, 2);
//FILE *fp = fopen("log", "wb+");
//cs_setopt_logfile(spider, fp);
//開始爬蟲
return cs_run(spider);
}
例子講解
cspider_t *spider = init_cspider();獲取初始的cspider。cs_setopt_xxx這類函數可以用來進行初始化設置。其中要注意的是: cs_setopt_process(spider,p,NULL);與cs_setopt_save(spider,s,stdout);,它們分別設置了解析函數p和數據持久化函數s,這兩個函數需要用戶自己實現,還有用戶自定義的指向上下文信息user_data的指針。
在解析函數中,用戶要定義解析的規則,並對解析得到的字元串可以調用saveString進行持久化,或者是調用addUrl將url加入到任務隊列中。在saveString中傳入的字元串會在用戶自定義的數據持久函數中得到處理。此時,用戶可以選擇輸出到文件或資料庫等。
最後調用cs_run(spider)即可啟動爬蟲。
具體的API參數可在這里查看
Ⅵ 除了python可以爬蟲還有哪些編程語言可以爬蟲
能夠做網路爬蟲的編程語言很多,包括PHP、Java、C/C++、Python等都能做爬蟲,都能達到抓取想要的數據資源。針對不同的環境,我們需要了解他們做爬蟲的優缺點,才能選出合適的開發環境。
(一)PHP
網路爬蟲需要快速的從伺服器中抓取需要的數據,有時數據量較大時需要進行多線程抓取。PHP雖然是世界上最好的語言,但是PHP對多線程、非同步支持不足,並發不足,而爬蟲程序對速度和效率要求極高,所以說PHP天生不是做爬蟲的。
(二)C/C++
C語言是一門面向過程、抽象化的通用程序設計語言,廣泛應用於底層開發,運行效率和性能是最強大的,但是它的學習成本非常高,需要有很好地編程知識基礎,對於初學者或者編程知識不是很好地程序員來說,不是一個很好的選擇。當然,能夠用C/C++編寫爬蟲程序,足以說明能力很強,但是絕不是最正確的選擇。
(三)Java
在網路爬蟲方面,作為Python最大的對手Java,擁有強大的生態圈。但是Java本身很笨重,代碼量大。由於爬蟲與反爬蟲的較量是持久的,也是頻繁的,剛寫好的爬蟲程序很可能就不能用了。爬蟲程序需要經常性的修改部分代碼。而Java的重構成本比較高,任何修改都會導致大量代碼的變動。
(四)Python
Python在設計上堅持了清晰劃一的風格,易讀、易維護,語法優美、代碼簡潔、開發效率高、第三方模塊多。並且擁有強大的爬蟲Scrapy,以及成熟高效的scrapy-redis分布式策略。實現同樣的爬蟲功能,代碼量少,而且維護方便,開發效率高。
Ⅶ 我想用c編寫一個爬蟲程序,可是看完一本c語言教程後,還是覺得只會編寫一些計算類的小代碼,要學會編寫
C++開發難度而言會大一些。你可以學學比如Python之類的,爬蟲找到好用的庫,沒多久就能做好了。
Ⅷ 各位好,有誰做過網路蜘蛛(爬蟲)啊可以提供C語言的源代碼給我不啊能幫我解釋一下更好,謝謝!
網上又好多,可以自己下載啊。http://bbs.chinaunix.net/thread-2163118-1-1.html
Ⅸ 怎麼在DOS下用C語言寫網路爬蟲
獲取cspider_t。
自定義user agent,cookie,timeout,proxy以及抓取線程和解析線程的最大數量。
添加初始要抓取的url到任務隊列。
編寫解析函數和數據持久化函數。
啟動爬蟲。
- #include<cspider/spider.h>
- /*
- 自定義的解析函數,d為獲取到的html頁面字元串
- */
- void p(cspider_t *cspider, char *d, void *user_data) {
- char *get[100];
- //xpath解析html
- int size = xpath(d, "//body/div[@class='wrap']/div[@class='sort-column area']/div[@class='column-bd cfix']/ul[@class='st-list cfix']/li/strong/a", get, 100);
- int i;
- for (i = 0; i < size; i++) {
- //將獲取到的電影名稱,持久化
- saveString(cspider, get[i]);
- }
- }
- /*
- 數據持久化函數,對上面解析函數中調用的saveString()函數傳入的數據,進行進一步的保存
- */
- void s(void *str, void *user_data) {
- char *get = (char *)str;
- FILE *file = (FILE*)user_data;
- fprintf(file, "%s ", get);
- return;
- }
- int main() {
- //初始化spider
- cspider_t *spider = init_cspider();
- char *agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0";
- //char *cookie = "bid=s3/yuH5Jd/I; ll=108288; viewed=1130500_24708145_6433169_4843567_1767120_5318823_1899158_1271597; __utma=30149280.927537245.1446813674.1446983217.1449139583.4; __utmz=30149280.1449139583.4.4.utmcsr=accounts.douban.com|utmccn=(referral)|utmcmd=referral|utmcct=/login; ps=y; [email protected]; dbcl2=58742090:QgZ2PSLiDLQ; ck=T9Wn; push_noty_num=0; push_doumail_num=7; ap=1; __utmb=30149280.0.10.1449139583; __utmc=30149280";
- //設置要抓取頁面的url
- cs_setopt_url(spider, "so.tv.sohu.com/list_p1100_p20_p3_u5185_u5730_p40_p5_p6_p77_p80_p9_2d1_p101_p11.html");
- //設置user agent
- cs_setopt_useragent(spider, agent);
- //cs_setopt_cookie(spider, cookie);
- //傳入解析函數和數據持久化函數的指針
- cs_setopt_process(spider, p, NULL);
- //s函數的user_data指針指向stdout
- cs_setopt_save(spider, s, stdout);
- //設置線程數量
- cs_setopt_threadnum(spider, DOWNLOAD, 2);
- cs_setopt_threadnum(spider, SAVE, 2);
- //FILE *fp = fopen("log", "wb+");
- //cs_setopt_logfile(spider, fp);
- //開始爬蟲
- return cs_run(spider);
- }
例子
先來看下簡單的爬蟲例子,會在後面詳細講解例子。
Ⅹ Python爬蟲是什麼
爬蟲一般指網路資源的抓取,通過編程語言撰寫爬蟲工具,抓取自己想要的數據以及內容。而在眾多編程語言之中,Python有豐富的網路抓取模塊,因此成為撰寫爬蟲的首選語言,並引起了學習熱潮。
Python作為一門編程語言而純粹的自由軟體,以簡潔清晰的語法和強制使用空白符號進行語句縮進的特點受到程序員的喜愛。用不同編程語言完成一個任務,C語言一共要寫1000行代碼,Java要寫100行代碼,而Python只需要20行,用Python來完成編程任務代碼量更少,代碼簡潔簡短而且可讀性強。
Python非常適合開發網路爬蟲,因為對比其他靜態編程語言,Python抓取網頁文檔的介面更簡潔;對比其他腳本語言,Python的urllib2包提供了較為完整的訪問網頁文檔的API。
Python爬蟲的工作流程是什麼?
Python爬蟲通過URL管理器,判斷是否有待爬URL,如果有待爬URL,通過調度器進行傳遞給下載器,下載URL內容,通過調度器傳送給解釋器,解析URL內容,將有價值數據和新的URL列表通過調度器傳遞給應用程序,輸出價值信息的過程。
Python是一門非常適合開發網路爬蟲的語言,提供了urllib、re、json、pyquery等模塊,同時還有很多成型框架,比如說Scrapy框架、PySpider爬蟲系統等,代碼十分簡潔方便,是新手學習網路爬蟲的首選語言。