php爬蟲採集數據並發執行問題(php多線程爬蟲)

本文目錄一覽:

如何提高爬蟲效率

提高爬蟲效率的方法

協程。採用協程,讓多個爬蟲一起工作,可以大幅度提高效率。

多進程。使用CPU的多個核,使用幾個核就能提高几倍。

多線程。將任務分成多個,並發(交替)的執行。

分布式爬蟲。讓多個設備去跑同一個項目,效率也能大幅提升。

打包技術。可以將python文件打包成可執行的exe文件,讓其在後台執行即可。

其他。比如,使用網速好的網絡等等。

如何用php 編寫網絡爬蟲

php不太適合用來寫網絡爬蟲,因為幾乎沒有現成的框架,或者成熟的下載機制,也不太適合做並發處理.

下載頁面的話除了一個curl,就是file_get_contents,或者curl_multi來做並發請求.curl可以代理端口,虛假ip,帶cookie,帶header請求目標頁面,下載完成之後解析頁面可以用queryList來解析html.寫法類似jQuery.

提供給你我之前寫的類:curl.php  希望可以幫到你.

QueryList.php和phpQuery.php由於文件太大了,沒辦法貼上來

?php

class Http {

    public function curlRequest($url, $postData = ”, $timeOut = 10, $httpHeader = array()) {

        $handle = curl_init ();

        curl_setopt ( $handle, CURLOPT_URL, $url );

        if ($httpHeader) {

            curl_setopt($handle, CURLOPT_HTTPHEADER, $httpHeader);

        }

        curl_setopt ( $handle, CURLOPT_RETURNTRANSFER, true );

        curl_setopt ( $handle, CURLOPT_HEADER, 0 );                                                                curl_setopt ( $handle, CURLOPT_TIMEOUT, $timeOut );

        curl_setopt ( $handle, CURLOPT_FOLLOWLOCATION, 1 );

        curl_setopt ( $handle, CURLOPT_SSL_VERIFYPEER, false );

        curl_setopt ( $handle, CURLOPT_SSL_VERIFYHOST, false );

        curl_setopt ( $handle, CURLOPT_USERAGENT, ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36’);        curl_setopt ( $handle, CURLOPT_ENCODING, ‘gzip,deflate,sdch’);

        if (! empty ( $postData )) {

            curl_setopt ( $handle, CURLOPT_POST, 1 );

            curl_setopt ( $handle, CURLOPT_POSTFIELDS, $postData);

        }

        $result[‘response’] = curl_exec ( $handle );

        $result[‘httpStatus’] = curl_getinfo ( $handle, CURLINFO_HTTP_CODE );

        $result[‘fullInfo’] = curl_getinfo ( $handle );

        $result[‘errorMsg’] = ”;

        $result[‘errorNo’] = 0;

        if (curl_errno($handle)) {

            $result[‘errorMsg’] = curl_error($handle);

            $result[‘errorNo’] = curl_errno($handle);

        }

        curl_close ( $handle );

        return $result;

    }

}

?

php中產生的並發問題一般如何解決?

您好,並發問題一般使用nosql進行解決,例如Redis等進行削峰處理

如何處理數據庫並發問題

想要知道如何處理數據並發,自然需要先了解數據並發。

什麼是數據並發操作呢?

就是同一時間內,不同的線程同時對一條數據進行讀寫操作。

在互聯網時代,一個系統常常有很多人在使用,因此就可能出現高並發的現象,也就是不同的用戶同時對一條數據進行操作,如果沒有有效的處理,自然就會出現數據的異常。而最常見的一種數據並發的場景就是電商中的秒殺,成千上萬個用戶對在極端的時間內,搶購一個商品。針對這種場景,商品的庫存就是一個需要控制的數據,而多個用戶對在同一時間對庫存進行重寫,一個不小心就可能出現超賣的情況。

針對這種情況,我們如何有效的處理數據並發呢?

第一種方案、數據庫鎖

從鎖的基本屬性來說,可以分為兩種:一種是共享鎖(S),一種是排它鎖(X)。在MySQL的數據庫中,是有四種隔離級別的,會在讀寫的時候,自動的使用這兩種鎖,防止數據出現混亂。

這四種隔離級別分別是:

讀未提交(Read Uncommitted)

讀提交(Read Committed)

可重複讀(Repeated Read)

串行化(Serializable)

當然,不同的隔離級別,效率也是不同的,對於數據的一致性保證也就有不同的結果。而這些可能出現的又有哪些呢?

臟讀(dirty read)

當事務與事務之間沒有任何隔離的時候,就可能會出現臟讀。例如:商家想看看所有的訂單有哪些,這時,用戶A提交了一個訂單,但事務還沒提交,商家卻看到了這個訂單。而這時就會出現一種問題,當商家去操作這個訂單時,可能用戶A的訂單由於部分問題,導致數據回滾,事務沒有提交,這時商家的操作就會失去目標。

不可重複讀(unrepeatable read)

一個事務中,兩次讀操作出來的同一條數據值不同,就是不可重複讀。

例如:我們有一個事務A,需要去查詢一下商品庫存,然後做扣減,這時,事務B操作了這個商品,扣減了一部分庫存,當事務A再次去查詢商品庫存的時候,發現這一次的結果和上次不同了,這就是不可重複讀。

幻讀(phantom problem)

一個事務中,兩次讀操作出來的結果集不同,就是幻讀。

例如:一個事務A,去查詢現在已經支付的訂單有哪些,得到了一個結果集。這時,事務B新提交了一個訂單,當事務A再次去查詢時,就會出現,兩次得到的結果集不同的情況,也就是幻讀了。

那針對這些結果,不同的隔離級別可以幹什麼呢?

“讀未提(Read Uncommitted)”能預防啥?啥都預防不了。

“讀提交(Read Committed)”能預防啥?使用“快照讀(Snapshot Read)”方式,避免“臟讀”,但是可能出現“不可重複讀”和“幻讀”。

“可重複讀(Repeated Red)”能預防啥?使用“快照讀(Snapshot Read)”方式,鎖住被讀取記錄,避免出現“臟讀”、“不可重複讀”,但是可能出現“幻讀”。

“串行化(Serializable)”能預防啥?有效避免“臟讀”、“不可重複讀”、“幻讀”,不過運行效率奇差。

好了,鎖說完了,但是,我們的數據庫鎖,並不能有效的解決並發的問題,只是儘可能保證數據的一致性,當並發量特別大時,數據庫還是容易扛不住。那解決數據並發的另一個手段就是,儘可能的提高處理的速度。

因為數據的IO要提升難度比較大,那麼通過其他的方式,對數據進行處理,減少數據庫的IO,就是提高並發能力的有效手段了。

最有效的一種方式就是:緩存

想要減少並發出現的概率,那麼讀寫的效率越高,讀寫的執行時間越短,自然數據並發的可能性就變小了,並發性能也有提高了。

還是用剛才的秒殺舉例,我們為的就是保證庫存的數據不出錯,賣出一個商品,減一個庫存,那麼,我們就可以將庫存放在內存中進行處理。這樣,就能夠保證庫存有序的及時扣減,並且不出現問題。這樣,我們的數據庫的寫操作也變少了,執行效率也就大大提高了。

當然,常用的分布式緩存方式有:Redis和Memcache,Redis可以持久化到硬盤,而Memcache不行,應該怎麼選擇,就看具體的使用場景了。

當然,緩存畢竟使用的範圍有限,很多的數據我們還是必須持久化到硬盤中,那我們就需要提高數據庫的IO能力,這樣避免一個線程執行時間太長,造成線程的阻塞。

那麼,讀寫分離就是另一種有效的方式了

當我們的寫成為了瓶頸的時候,讀寫分離就是一種可以選擇的方式了。

我們的讀庫就只需要執行讀,寫庫就只需要執行寫,把讀的壓力從主庫中分離出去,讓主庫的資源只是用來保證寫的效率,從而提高寫操作的性能。

php curl 大量數據採集

這個需要配合js,打開一個html頁面,首先js用ajax請求頁面,返回第一個頁面信息確定處理完畢(ajax有強制同步功能),ajax再訪問第二個頁面。(或者根據服務器狀況,你可以同時提交幾個URL,跑幾個相同的頁面)

參數可以由js產生並傳遞url,php後台頁面根據URL抓頁面。然後ajax通過php,在數據庫或者是哪裡設一個標量,標明檢測到哪裡。由於前台的html頁面執行多少時候都沒問題,這樣php的內存限制和執行時間限制就解決了。

因為不會浪費大量的資源用一個頁面來跑一個瞬間500次的for循環了。(你的500次for循環死了原因可能是獲取的數據太多,大過了php限制的內存)

不過印象中curl好像也有強制同步的選項,就是等待一個抓取後再執行下一步。但是這個500次都是用一個頁面線程處理,也就是說肯定會遠遠大於30秒的默認執行時間。

如何將單機爬蟲的並發請求提高到50+qps

之前寫了個現在看來很不完美的小爬蟲,很多地方沒有處理好,比如說在知乎點開一個問題的時候,它的所有回答並不是全部加載好了的,當你拉到回答的尾部時,點擊加載更多,回答才會再加載一部分,所以說如果直接發送一個問題的請求鏈接,取得的頁面是不完整的。還有就是我們通過發送鏈接下載圖片的時候,是一張一張來下的,如果圖片數量太多的話,真的是下到你睡完覺它還在下,而且我們用nodejs寫的爬蟲,卻竟然沒有用到nodejs最牛逼的異步並發的特性,太浪費了啊。

思路

這次的的爬蟲是上次那個的升級版,不過呢,上次那個雖然是簡單,但是很適合新手學習啊。這次的爬蟲代碼在我的github上可以找到=NodeSpider。

整個爬蟲的思路是這樣的:在一開始我們通過請求問題的鏈接抓取到部分頁面數據,接下來我們在代碼中模擬ajax請求截取剩餘頁面的數據,當然在這裡也是可以通過異步來實現並發的,對於小規模的異步流程控制,可以用這個模塊=eventproxy,但這裡我就沒有用啦!我們通過分析獲取到的頁面從中截取出所有圖片的鏈接,再通過異步並發來實現對這些圖片的批量下載。

抓取頁面初始的數據很簡單啊,這裡就不做多解釋啦

/*獲取首屏所有圖片鏈接*/ var getInitUrlList=function(){ request.get(“”) .end(function(err,res){ if(err){ console.log(err); }else{ var $=cheerio.load(res.text); var answerList=$(“.zm-item-answer”); answerList.map(function(i,answer){ var images=$(answer).find(‘.zm-item-rich-text img’); images.map(function(i,image){ photos.push($(image).attr(“src”)); }); }); console.log(“已成功抓取”+photos.length+”張圖片的鏈接”); getIAjaxUrlList(); } }); }

模擬ajax請求獲取完整頁面

接下來就是怎麼去模擬點擊加載更多時發出的ajax請求了,去知乎看一下吧!

有了這些信息,就可以來模擬發送相同的請求來獲得這些數據啦。

/*每隔毫秒模擬發送ajax請求,並獲取請求結果中所有的圖片鏈接*/ var getIAjaxUrlList=function(offset){ request.post(“”) .set(config) .send(“method=next¶ms=%B%url_token%%A%C%pagesize%%A%C%offset%%A” +offset+ “%D_xsrf=adfdeee”) .end(function(err,res){ if(err){ console.log(err); }else{ var response=JSON.parse(res.text);/*想用json的話對json序列化即可,提交json的話需要對json進行反序列化*/ if(response.msgresponse.msg.length){ var $=cheerio.load(response.msg.join(“”));/*把所有的數組元素拼接在一起,以空白符分隔,不要這樣join(),它會默認數組元素以逗號分隔*/ var answerList=$(“.zm-item-answer”); answerList.map(function(i,answer){ var images=$(answer).find(‘.zm-item-rich-text img’); images.map(function(i,image){ photos.push($(image).attr(“src”)); }); }); setTimeout(function(){ offset+=; console.log(“已成功抓取”+photos.length+”張圖片的鏈接”); getIAjaxUrlList(offset); },); }else{ console.log(“圖片鏈接全部獲取完畢,一共有”+photos.length+”條圖片鏈接”); // console.log(photos); return downloadImg(); } } }); }

在代碼中post這條請求,把原請求頭和請求參數複製下來,作為我們的請求頭和請求參數,superagent的set方法可用來設置請求頭,send方法可以用來發送請求參數。我們把請求參數中的offset初始為20,每隔一定時間offset再加20,再重新發送請求,這樣就相當於我們每隔一定時間發送了一條ajax請求,獲取到最新的20條數據,每獲取到了數據,我們再對這些數據進行一定的處理,讓它們變成一整段的html,便於後面的提取鏈接處理。 異步並發控制下載圖片再獲取完了所有的圖片鏈接之後,即判定response.msg為空時,我們就要對這些圖片進行下載了,不可能一條一條下對不對,因為如你所看到的,我們的圖片足足有

沒錯,2萬多張,不過幸好nodejs擁有神奇的單線程異步特性,我們可以同時對這些圖片進行下載。但這個時候問題來了,聽說同時發送請求太多的話會被網站封ip噠!這是真的嗎?我不知道啊,沒試過,因為我也不想去試( ̄ー ̄〃),所以這個時候我們就需要對異步並發數量進行一些控制了。

在這裡用到了一個神奇的模塊=async,它不僅能幫我們拜託難以維護的回調金字塔惡魔,還能輕鬆的幫我們進行異步流程的管理。具體看文檔啦,因為我自己也不怎麼會用,這裡就只用到了一個強大的async.mapLimit方法。真的很厲害哦。

var requestAndwrite=function(url,callback){ request.get(url).end(function(err,res){ if(err){ console.log(err); console.log(“有一張圖片請求失敗啦…”); }else{ var fileName=path.basename(url); fs.writeFile(“./img/”+fileName,res.body,function(err){ if(err){ console.log(err); console.log(“有一張圖片寫入失敗啦…”); }else{ console.log(“圖片下載成功啦”); callback(null,”successful !”); /*callback貌似必須調用,第二個參數將傳給下一個回調函數的result,result是一個數組*/ } }); } }); } var downloadImg=function(asyncNum){ /*有一些圖片鏈接地址不完整沒有“http:”頭部,幫它們拼接完整*/ for(var i=;iphotos.length;i++){ if(photos[i].indexof(“http”)=”==-){” photos[i]=”http:” +photos[i];=”” }=”” console.log(“即將異步並發下載圖片,當前並發數為:”+asyncnum);=”” async.maplimit(photos,asyncnum,function(photo,callback){=”” console.log(“已有”+asyncnum+”張圖片進入下載隊列”);=”” requestandwrite(photo,callback);=”” },function(err,result){=”” if(err){=”” console.log(err);=”” }else{=”” console.log(result);=”會輸出一個有萬多個“successful”字符串的數組” console.log(“全部已下載完畢!”);=”” });=”” };=”” 先看這裡=

mapLimit方法的第一個參數photos是所有圖片鏈接的數組,也是我們並發請求的對象,asyncNum是限制並發請求的數量,如果沒有這個參數的話,將會有同時兩萬多條請求發送過去,嗯,你的ip就會被成功的封掉,但當我們有這個參數時,比如它的值是10,則它一次就只會幫我們從數組中取10條鏈接,執行並發的請求,這10條請求都得到響應後,再發送下10條請求。告訴泥萌,並發到同時100條沒有事的,下載速度超級快,再往上就不知道咯,你們來告訴我…

以上所述給大家介紹了Nodejs爬蟲進階教程之異步並發控制的相關知識,希望對大家有所幫助。

原創文章,作者:GVOKV,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/316519.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
GVOKV的頭像GVOKV
上一篇 2025-01-09 12:14
下一篇 2025-01-09 12:14

相關推薦

  • Python官網中文版:解決你的編程問題

    Python是一種高級編程語言,它可以用於Web開發、科學計算、人工智能等領域。Python官網中文版提供了全面的資源和教程,可以幫助你入門學習和進一步提高編程技能。 一、Pyth…

    編程 2025-04-29
  • Python讀取CSV數據畫散點圖

    本文將從以下方面詳細闡述Python讀取CSV文件並畫出散點圖的方法: 一、CSV文件介紹 CSV(Comma-Separated Values)即逗號分隔值,是一種存儲表格數據的…

    編程 2025-04-29
  • Python爬蟲可以爬哪些網站

    Python是被廣泛運用於數據處理和分析領域的編程語言之一。它具有易用性、靈活性和成本效益高等特點,因此越來越多的人開始使用它進行網站爬取。本文將從多個方面詳細闡述,Python爬…

    編程 2025-04-29
  • 如何解決WPS保存提示會導致宏不可用的問題

    如果您使用過WPS,可能會碰到在保存的時候提示“文件中含有宏,保存將導致宏不可用”的問題。這個問題是因為WPS在默認情況下不允許保存帶有宏的文件,為了解決這個問題,本篇文章將從多個…

    編程 2025-04-29
  • Python中讀入csv文件數據的方法用法介紹

    csv是一種常見的數據格式,通常用於存儲小型數據集。Python作為一種廣泛流行的編程語言,內置了許多操作csv文件的庫。本文將從多個方面詳細介紹Python讀入csv文件的方法。…

    編程 2025-04-29
  • 如何用Python統計列表中各數據的方差和標準差

    本文將從多個方面闡述如何使用Python統計列表中各數據的方差和標準差, 並給出詳細的代碼示例。 一、什麼是方差和標準差 方差是衡量數據變異程度的統計指標,它是每個數據值和該數據值…

    編程 2025-04-29
  • Python多線程讀取數據

    本文將詳細介紹多線程讀取數據在Python中的實現方法以及相關知識點。 一、線程和多線程 線程是操作系統調度的最小單位。單線程程序只有一個線程,按照程序從上到下的順序逐行執行。而多…

    編程 2025-04-29
  • 爬蟲是一種程序

    爬蟲是一種程序,用於自動獲取互聯網上的信息。本文將從如下多個方面對爬蟲的意義、運行方式、應用場景和技術要點等進行詳細的闡述。 一、爬蟲的意義 1、獲取信息:爬蟲可以自動獲取互聯網上…

    編程 2025-04-29
  • Python爬取公交數據

    本文將從以下幾個方面詳細闡述python爬取公交數據的方法: 一、準備工作 1、安裝相關庫 import requests from bs4 import BeautifulSou…

    編程 2025-04-29
  • Python兩張表數據匹配

    本篇文章將詳細闡述如何使用Python將兩張表格中的數據匹配。以下是具體的解決方法。 一、數據匹配的概念 在生活和工作中,我們常常需要對多組數據進行比對和匹配。在數據量較小的情況下…

    編程 2025-04-29

發表回復

登錄後才能評論