2017-02-10 79 views
0

我正在構建一個包含大約140個URL的數據庫的PHP應用程序。使用PHP curl下載許多網頁

目標是下載這些網頁內容的副本。

我已經編寫了從我的數據庫中讀取URL的代碼,然後使用curl來獲取頁面的副本。然後它獲取<body> </body>之間的所有內容,並將其寫入文件。它還考慮到重定向,例如如果我轉到一個URL並且響應代碼是302,它將遵循適當的鏈接。到現在爲止還挺好。

這一切都適用於一些網址(也許20左右),但然後我的腳本超時由於max_execution_time設置爲30秒。我不想重寫或增加這個,因爲我覺得這是一個糟糕的解決方案。

我想到了2個解決方法,但想知道這些是好還是壞的方法,或者如果有更好的方法。

第一種方法是在數據庫查詢上使用LIMIT,以便一次將任務分成20行(即如果有140行,則分別運行腳本7次)。我從這個方法中明白,它仍然需要調用script,download.php,7個不同的時間,所以需要通過限制數字。

第二種方法是在腳本中傳入我想要的URL(例如download.php?id=2)的每個數據庫記錄的ID,然後對它們執行多個Ajax請求(download.php?id=2, download.php?id=3, download.php?id=4等)。基於$_GET['id']它可以做一個查詢來查找數據庫中的URL等。理論上我會做140個單獨的請求,因爲它是每個URL設置1個請求。

我讀過一些其他指出排隊系統的帖子,但這些都超出了我的理解。如果這是最好的方法,那麼是否有一個值得一看的特定系統?

任何幫助,將不勝感激。

編輯:目前有140個網址,而且這個網址可能會隨着時間推移而增加。所以我正在尋找一種解決方案,可以在沒有超時限制的情況下進行擴展。

+0

更改max_execution_time可能是最好的解決方案,因爲您確實不知道要花費多長時間才能抓取140頁,或者服務器是否會滯後,並使某些請求比其他請求花費更長的時間。 – Brogan

+0

延長超時並不是一個糟糕的解決方案。使用['set_time_limit(30)'](http://php.net/manual/en/function.set-time-limit.php)循環的每個步驟(或任何對於單個頁面合理的)。這是一個合理的說法,「我將允許每CURL呼叫X秒」。 – apokryfos

+1

我會用ajax調用方法。所以你可以抓住數據庫中的所有記錄,迭代它發送ajax調用,然後在完成時報告。接收到調用(並進行工作)的腳本可能會報告並說出如下內容:「X中的X已完成,Y中有錯誤」 – LordNeo

回答

2

我不同意你的邏輯,如果腳本運行良好,需要更多時間完成,只是給它更多的時間,這不是一個糟糕的解決方案。你的建議使事情變得更加複雜,並且不能很好地擴展如果你的網址增加。

我會建議你的腳本移動到沒有時間限制的命令行,而不是使用瀏覽器來執行它。

+0

完全相反,當列表變大時,增加超時將不會升級。你不能無限增加超時。 ajax調用將分離每個進程並將其隔離爲一個單獨的線程,以便他可以獲得多個結果(成功/失敗),而無需從頭開始重新運行所有內容。 – LordNeo

+1

這不是我所建議的,我說移動到沒有時間限制的命令行。 set_time_limit(0)的equivelant; –

+0

無法讓命令行無限期地打開,您不知道列表是否會像10.000一樣大或保持不變。 – LordNeo

1

當你有一個未知的列表,這將需要一個未知的時間異步調用的路要走。

將你的腳本分成單頁下載(就像你建議的,download.php?id=X)。

從「主」腳本中獲取數據庫中的列表,遍歷它並向每個腳本發送一個ajax調用。由於所有的電話都會立即被觸發,請檢查您的帶寬和CPU時間。您可以使用成功回調將其分解爲「X活動任務」。

您可以設置download.php文件返回成功數據或將其保存到數據庫中,並使用網站的ID和調用結果。我推薦以後的版本,因爲您可以稍後離開主腳本並獲取結果。

你不能無限期地增加時間限制,不能等待無限期的時間來完成請求,所以你需要一個「消失和忘記」,這就是異步調用最好的。

@apokryfos指出,根據這種「備份」的時機,你可以將它安裝到任務調度器(如chron)中。如果你把它叫做「on demand」,把它放在一個gui中,如果你把它稱爲「每x次」,把一個指向主腳本的時間任務放在它上面,它也會這樣做。

+1

上的差異。比如適合任務調度器而不是客戶端UI的東西。 CLI可能是一種更好的方法。 – apokryfos

0

您所描述的內容聽起來像是控制檯的工作。瀏覽器供用戶看,但你的任務是程序員將運行的東西,所以使用控制檯。或者安排文件以cron-job或類似的方式由開發人員處理。

0

使用stream_socket_client()同時執行所有請求。將所有套接字ID保存在一個數組中

然後使用stream_select()循環訪問ID數組以讀取響應。

這幾乎就像PHP中的多任務處理一樣。