首頁 >web前端 >js教程 >網絡與節點,phantomjs和騎手一起爬行

網絡與節點,phantomjs和騎手一起爬行

Jennifer Aniston
Jennifer Aniston原創
2025-02-18 11:57:10215瀏覽

網絡與節點,phantomjs和騎手一起爬行

鑰匙要點

  • >利用node.js和npm有效地為Web爬網和其他命令行任務設置自定義CLI縮影。 >
  • >使用Phantomjs和Horseman軟件包來模擬瀏覽器中的用戶互動,從而增強了自動化的Web爬行功能。
  • 結合了騎士方法的鏈接,以執行複雜的動作序列,從而在網頁中進行動態交互。
  • 利用騎士中的evaluate()方法直接從DOM中提取靈活的腳本和數據提取,可用於諸如污損檢測之類的任務。
  • >利用Horseman的屏幕截圖功能在網上爬行期間捕獲和保存屏幕截圖,以幫助視覺QA測試等任務。
  • >確保每次使用後都關閉騎士實例,以防止孤立的phantomjs過程,保持系統性能和穩定性。
  • >
>本文由盧卡斯·懷特(Lukas White)進行了同行評審。感謝SitePoint所有的同行評審員製作SitePoint內容的最佳功能! 在項目過程中,發現自己需要編寫自定義腳本以執行各種操作是很普遍的。這種通常通過命令行(CLI)執行的一次性腳本幾乎可用於任何類型的任務。這些年來編寫了許多這樣的腳本後,我已經成長為欣賞花費少量時間的價值,以實現定制的CLI微框架來促進這一過程。幸運的是,Node.js及其廣泛的包裝生態系統NPM使它很容易做到這一點。無論是解析文本文件還是運行ETL,都可以使用慣例,使以高效且結構化的方式添加新功能變得容易。 > >不一定與命令行相關,但網絡爬行通常用於某些問題域,例如自動化功能測試和污損檢測。本教程演示瞭如何實施輕量級的CLI框架,其支持的行動圍繞著網絡爬行。希望這將使您的創意果汁流動,無論您的興趣是爬行還是指揮專線。涵蓋的技術包括node.js,phantomjs,以及與爬行和CLI有關的各種NPM軟件包。

可以在GitHub上找到本教程的源代碼。為了運行示例,您需要同時安裝node.js和phantomjs。可以在此處找到用於下載和安裝的說明:node.js,phantomjs。

>設置基本命令行框架

任何CLI框架的核心是將命令轉換為一個或多個可選或必需的參數,轉換為具體操作的概念。在這方面非常有用的兩個NPM軟件包是指揮官和提示。

指揮官允許您定義支持哪些參數,同時提示允許您(足夠適當地)提示用戶在運行時輸入。最終結果是一個句法甜蜜的界面,用於基於某些用戶提供的數據,以動態行為執行各種動作。

>

說,例如,我們希望我們的命令看起來像這樣:

>
$ <span>node run.js -x hello_world
</span>

我們的入口點(run.js)定義了這樣的參數:

>
program
  <span>.version('1.0.0')
</span>  <span>.option('-x --action-to-perform [string]', 'The type of action to perform.')
</span>  <span>.option('-u --url [string]', 'Optional URL used by certain actions')
</span>  <span>.parse(process.argv);
</span>

並定義了這樣的各種用戶輸入案例:

>
<span>var performAction = require('./actions/' + program.actionToPerform)
</span>
<span>switch (program.actionToPerform) {
</span>  <span>case 'hello_world':
</span>    prompt<span>.get([{
</span>
      <span>// What the property name should be in the result object
</span>      <span>name: 'url',
</span>
      <span>// The prompt message shown to the user
</span>      <span>description: 'Enter a URL',
</span>
      <span>// Whether or not the user is required to enter a value
</span>      <span>required: true,
</span>
      <span>// Validates the user input
</span>      <span>conform: function (value) {
</span>
        <span>// In this case, the user must enter a valid URL
</span>        <span>return validUrl.isWebUri(value);
</span>      <span>}
</span>    <span>}], function (err<span>, result</span>) {
</span>
      <span>// Perform some action following successful input
</span>      <span>performAction(phantomInstance, result.url);
</span>    <span>});
</span>    <span>break;
</span><span>}
</span>
在這一點上,我們已經定義了一個基本路徑,可以通過該路徑指定執行操作,並添加了一個提示以接受URL。我們只需要添加一個模塊來處理該操作的邏輯即可。我們可以通過將一個名為hello_world.js的文件添加到操作目錄中來做到這一點:

>

如您所見,該模塊期望提供一個phantomjs對象(Phantominstance)和URL(URL)的實例。我們將暫時地定義Phantomjs實例的細節,但是目前足以看到我們為觸發特定動作奠定了基礎。既然我們已經制定了一定的慣例,我們可以輕鬆地以定義和理智的方式添加新的動作。
<span>'use strict';
</span>
<span>/**
</span><span> * <span>@param Horseman phantomInstance
</span></span><span> * <span>@param string url
</span></span><span> */
</span>module<span>.exports = function (phantomInstance<span>, url</span>) {
</span>
  <span>if (!url || typeof url !== 'string') {
</span>    <span>throw 'You must specify a url to ping';
</span>  <span>} else {
</span>    <span>console.log('Pinging url: ', url);
</span>  <span>}
</span>
  phantomInstance
    <span>.open(url)
</span>    <span>.status()
</span>    <span>.then(function (statusCode) {
</span>      <span>if (Number(statusCode) >= 400) {
</span>        <span>throw 'Page failed with status: ' + statusCode;
</span>      <span>} else {
</span>        <span>console.log('Hello world. Status code returned: ', statusCode);
</span>      <span>}
</span>    <span>})
</span>    <span>.catch(function (err) {
</span>      <span>console.log('Error: ', err);
</span>    <span>})
</span>
    <span>// Always close the Horseman instance
</span>    <span>// Otherwise you might end up with orphaned phantom processes
</span>    <span>.close();
</span><span>};
</span>
> 使用騎兵

爬行

Horseman是一個node.js軟件包,提供了一個強大的接口,用於創建和與phantomjs進程進行交互。對騎士及其功能的全面解釋將需要其自己的文章,但足以說,它使您可以輕鬆地模擬人類用戶在瀏覽器中可能表現出的任何行為。 Horseman提供了廣泛的配置選項,包括自動注入jQuery和忽略SSL證書警告之類的東西。它還為曲奇處理和拍攝屏幕截圖提供了功能。

>每次我們通過CLI框架觸發操作時,我們的輸入腳本(RUN.JS)實例化騎士實例並將其傳遞到指定的操作模塊。在偽代碼中,它看起來像這樣:

>

現在,當我們運行命令時,騎手實例和輸入URL將傳遞到Hello_world模塊,導致Phantomjs請求URL,捕獲其狀態代碼並將狀態打印到控制台。我們剛剛使用騎馬者進行了第一個真正的善意爬行。 giddyup!

<span>var phantomInstance = new Horseman({
</span>  <span>phantomPath: '/usr/local/bin/phantomjs',
</span>  <span>loadImages: true,
</span>  <span>injectJquery: true,
</span>  <span>webSecurity: true,
</span>  <span>ignoreSSLErrors: true
</span><span>});
</span>
<span>performAction(phantomInstance, ...);
</span>

複合互動的騎士方法網絡與節點,phantomjs和騎手一起爬行 到目前為止,我們已經研究了非常簡單的騎士用法,但是當我們將其方法鏈接在一起以在瀏覽器中執行一系列操作時,包裝可以做得更多。為了演示其中一些功能,讓我們定義一個動作,該操作模擬了通過GitHub導航以創建新存儲庫的用戶。

請注意:此示例純粹是出於演示目的,不應被視為創建GitHub存儲庫的可行方法。這僅僅是一個人如何使用騎手與Web應用程序進行交互的示例。如果您有興趣以自動方式創建存儲庫,則應使用官方的GitHub API。

讓我們假設新的爬網會像這樣觸發:

>按照我們已經制定的CLI框架的約定,我們需要在名為create_repo.js的操作目錄中添加一個新模塊。與我們以前的“ Hello World”示例一樣,create_repo模塊導出一個包含該動作的所有邏輯的單個函數。
$ <span>node run.js -x hello_world
</span>

請注意,在此操作中,我們將更多的參數傳遞給導出的函數,而不是以前。這些參數包括用戶名,密碼和存儲庫。一旦用戶成功完成了及時挑戰,我們將從run.js傳遞這些值。 >
program
  <span>.version('1.0.0')
</span>  <span>.option('-x --action-to-perform [string]', 'The type of action to perform.')
</span>  <span>.option('-u --url [string]', 'Optional URL used by certain actions')
</span>  <span>.parse(process.argv);
</span>
>在發生任何事情之前,我們必須添加邏輯。我們通過將案例添加到我們的主開關語句中來做到這一點:

>現在我們將此掛鉤添加到run.js,當用戶輸入相關數據時,它將傳遞給操作,從而使我們可以繼續進行爬網。

至於Create_repo爬網邏輯本身,我們使用騎手的方法來導航到GitHub登錄頁面,輸入提供的用戶名和密碼,然後提交表單:>
<span>var performAction = require('./actions/' + program.actionToPerform)
</span>
<span>switch (program.actionToPerform) {
</span>  <span>case 'hello_world':
</span>    prompt<span>.get([{
</span>
      <span>// What the property name should be in the result object
</span>      <span>name: 'url',
</span>
      <span>// The prompt message shown to the user
</span>      <span>description: 'Enter a URL',
</span>
      <span>// Whether or not the user is required to enter a value
</span>      <span>required: true,
</span>
      <span>// Validates the user input
</span>      <span>conform: function (value) {
</span>
        <span>// In this case, the user must enter a valid URL
</span>        <span>return validUrl.isWebUri(value);
</span>      <span>}
</span>    <span>}], function (err<span>, result</span>) {
</span>
      <span>// Perform some action following successful input
</span>      <span>performAction(phantomInstance, result.url);
</span>    <span>});
</span>    <span>break;
</span><span>}
</span>

我們通過等待表單提交頁面加載來繼續鏈條:

之後,我們使用jQuery來確定登錄是否成功:>

如果登錄失敗,則會拋出錯誤。否則,我們將繼續鏈接方法以導航到我們的個人資料頁面:
<span>'use strict';
</span>
<span>/**
</span><span> * <span>@param Horseman phantomInstance
</span></span><span> * <span>@param string url
</span></span><span> */
</span>module<span>.exports = function (phantomInstance<span>, url</span>) {
</span>
  <span>if (!url || typeof url !== 'string') {
</span>    <span>throw 'You must specify a url to ping';
</span>  <span>} else {
</span>    <span>console.log('Pinging url: ', url);
</span>  <span>}
</span>
  phantomInstance
    <span>.open(url)
</span>    <span>.status()
</span>    <span>.then(function (statusCode) {
</span>      <span>if (Number(statusCode) >= 400) {
</span>        <span>throw 'Page failed with status: ' + statusCode;
</span>      <span>} else {
</span>        <span>console.log('Hello world. Status code returned: ', statusCode);
</span>      <span>}
</span>    <span>})
</span>    <span>.catch(function (err) {
</span>      <span>console.log('Error: ', err);
</span>    <span>})
</span>
    <span>// Always close the Horseman instance
</span>    <span>// Otherwise you might end up with orphaned phantom processes
</span>    <span>.close();
</span><span>};
</span>

>在我們的個人資料頁面上,我們將導航到我們的存儲庫標籤:>
<span>var phantomInstance = new Horseman({
</span>  <span>phantomPath: '/usr/local/bin/phantomjs',
</span>  <span>loadImages: true,
</span>  <span>injectJquery: true,
</span>  <span>webSecurity: true,
</span>  <span>ignoreSSLErrors: true
</span><span>});
</span>
<span>performAction(phantomInstance, ...);
</span>

在我們的存儲庫選項卡時,我們檢查是否已經存在帶有指定名稱的存儲庫。如果是這樣,那麼我們會丟下錯誤。如果不是,那麼我們繼續我們的順序:

$ <span>node run.js -x create_repo
</span>

假設沒有錯誤,我們通過編程單擊“新存儲庫”按鈕並等待下一頁:

module<span>.exports = function (phantomInstance<span>, username, password, repository</span>) {
</span>
  <span>if (!username || !password || !repository) {
</span>    <span>throw 'You must specify login credentials and a repository name';
</span>  <span>}
</span>
  <span>...
</span><span>}
</span>

之後,我們輸入提供的存儲庫名稱並提交表格:>

<span>switch (program.actionToPerform) {
</span>
  <span>case 'create_repo':
</span>    prompt<span>.get([{
</span>       <span>name: 'repository',
</span>       <span>description: 'Enter repository name',
</span>       <span>required: true
</span>    <span>}, {
</span>       <span>name: 'username',
</span>       <span>description: 'Enter GitHub username',
</span>       <span>required: true
</span>     <span>}, {
</span>       <span>name: 'password',
</span>       <span>description: 'Enter GitHub password',
</span>       <span>hidden: true,
</span>       <span>required: true
</span>    <span>}], function (err<span>, result</span>) {
</span>      <span>performAction(
</span>        phantomInstance<span>,
</span>        result<span>.username,
</span>        result<span>.password,
</span>        result<span>.repository
</span>      <span>);
</span>    <span>});
</span>    <span>break;
</span>
    <span>...
</span>
>一旦到達生成頁面,我們就會知道存儲庫是創建的:>

與任何騎馬爬行一樣,至關重要的是,我們結束了騎馬的實例:
phantomInstance
  <span>.open('https://github.com/login')
</span>  <span>.type('input[name="login"]', username)
</span>  <span>.type('input[name="password"]', password)
</span>  <span>.click('input[name="commit"]')
</span>

>未能關閉騎士實例可能會導致機器上的孤立phantomjs處理。
<span>.waitForNextPage()
</span>
>爬行以收集數據

在這一點上,我們已經組裝了一系列靜態序列,以編程方式在GitHub上創建一個新的存儲庫。為此,我們鏈接了一系列的騎手方法。

這種方法對於事先已知的特定結構和行為模式可能很有用,但是,您可能會發現您需要在某個時候實現更靈活的腳本。如果您的動作序列有可能根據上下文變化或產生多個不同的結果,則可能是這種情況。如果您需要從DOM中提取數據,也將是這種情況。

在這種情況下,您可以使用Horseman的evaliate()方法,它允許您通過注入內聯或外部鏈接JavaScript來執行瀏覽器中的自由形式交互。

>

>本節演示了從頁面中提取基本數據的示例(在這種情況下,錨點鏈接)。可能需要這種情況的一種情況是構建一個污損檢測軌,以擊中域上的每個URL。

與我們的最後一個示例一樣,我們必須首先在操作目錄中添加一個新模塊:>

,然後在run.js中為新操作添加一個鉤子:
$ <span>node run.js -x hello_world
</span>
>

現在,此代碼已經到位,我們可以通過運行以下命令來從任何給定的頁面提取鏈接:>
program
  <span>.version('1.0.0')
</span>  <span>.option('-x --action-to-perform [string]', 'The type of action to perform.')
</span>  <span>.option('-u --url [string]', 'Optional URL used by certain actions')
</span>  <span>.parse(process.argv);
</span>

>此操作演示了從頁面上提取數據,並且不會利用騎手內置的任何瀏覽器操作。它直接執行您在estuation()方法中放置的任何JavaScript,並且會像在瀏覽器環境中本地運行一樣。

>
<span>var performAction = require('./actions/' + program.actionToPerform)
</span>
<span>switch (program.actionToPerform) {
</span>  <span>case 'hello_world':
</span>    prompt<span>.get([{
</span>
      <span>// What the property name should be in the result object
</span>      <span>name: 'url',
</span>
      <span>// The prompt message shown to the user
</span>      <span>description: 'Enter a URL',
</span>
      <span>// Whether or not the user is required to enter a value
</span>      <span>required: true,
</span>
      <span>// Validates the user input
</span>      <span>conform: function (value) {
</span>
        <span>// In this case, the user must enter a valid URL
</span>        <span>return validUrl.isWebUri(value);
</span>      <span>}
</span>    <span>}], function (err<span>, result</span>) {
</span>
      <span>// Perform some action following successful input
</span>      <span>performAction(phantomInstance, result.url);
</span>    <span>});
</span>    <span>break;
</span><span>}
</span>
>在本節中應注意的最後一件事,該部分提到了較早的提及:不僅可以使用estaution()方法在瀏覽器中執行自定義JavaScript,而且還可以在運行之前將外部腳本注入運行時環境您的評估邏輯。可以這樣做:

>通過擴展上面的邏輯,您幾乎可以在任何網站上執行任何操作。

>
<span>'use strict';
</span>
<span>/**
</span><span> * <span>@param Horseman phantomInstance
</span></span><span> * <span>@param string url
</span></span><span> */
</span>module<span>.exports = function (phantomInstance<span>, url</span>) {
</span>
  <span>if (!url || typeof url !== 'string') {
</span>    <span>throw 'You must specify a url to ping';
</span>  <span>} else {
</span>    <span>console.log('Pinging url: ', url);
</span>  <span>}
</span>
  phantomInstance
    <span>.open(url)
</span>    <span>.status()
</span>    <span>.then(function (statusCode) {
</span>      <span>if (Number(statusCode) >= 400) {
</span>        <span>throw 'Page failed with status: ' + statusCode;
</span>      <span>} else {
</span>        <span>console.log('Hello world. Status code returned: ', statusCode);
</span>      <span>}
</span>    <span>})
</span>    <span>.catch(function (err) {
</span>      <span>console.log('Error: ', err);
</span>    <span>})
</span>
    <span>// Always close the Horseman instance
</span>    <span>// Otherwise you might end up with orphaned phantom processes
</span>    <span>.close();
</span><span>};
</span>
使用騎手屏幕截圖

>我想證明的最終用例是您將如何使用Horseman拍攝屏幕截圖。我們可以使用Horseman的ScreenShotBase64()方法來完成此操作,該方法返回代表屏幕截圖的base64編碼字符串。

與我們上一個示例一樣,我們必須首先在操作目錄中添加一個新模塊:>

,然後在run.js中為新操作添加一個鉤子:

>

<span>var phantomInstance = new Horseman({
</span>  <span>phantomPath: '/usr/local/bin/phantomjs',
</span>  <span>loadImages: true,
</span>  <span>injectJquery: true,
</span>  <span>webSecurity: true,
</span>  <span>ignoreSSLErrors: true
</span><span>});
</span>
<span>performAction(phantomInstance, ...);
</span>
現在,您可以使用以下命令進行屏幕截圖:

>

$ <span>node run.js -x create_repo
</span>
>使用base64編碼字符串的原因(例如,保存實際圖像)是它們是表示原始圖像數據的便捷方法。這個堆疊式的答案更詳細。

>

如果要保存實際映像,則使用屏幕截圖()方法。
module<span>.exports = function (phantomInstance<span>, username, password, repository</span>) {
</span>
  <span>if (!username || !password || !repository) {
</span>    <span>throw 'You must specify login credentials and a repository name';
</span>  <span>}
</span>
  <span>...
</span><span>}
</span>
>

結論

本教程試圖展示自定義的CLI微框架和一些基本的邏輯,用於使用Horseman軟件包來利用Phantomjs,以爬Node.js爬網。雖然使用CLI框架可能會使許多項目受益,但爬行通常僅限於非常特定的問題域。一個共同的領域是質量保證(QA),可以將爬網用於功能和用戶界面測試。另一個領域是安全性,例如,您可能想定期爬網,以檢測到它是否已被污損或折衷。

>

無論您的項目可能是什麼情況,請確保清楚地定義您的目標並儘可能不引人注目。在可能的情況下獲得許可,請在最大程度上禮貌,並註意永遠不要DDOS。如果您懷疑自己正在產生大量的自動流量,那麼您可能會重新評估您的目標,實施或許可水平。

經常詢問的問題(常見問題解答)有關網絡爬行的節點和phantomjs騎手

Web爬網和Web刮擦之間有什麼區別?

Web爬網和Web刮擦是兩個不同的過程,儘管它們通常可以互換使用。網絡爬行是系統瀏覽網絡的過程,通常由機器人或蜘蛛進行。它涉及索引網站的內容和以下鏈接到其他網頁。另一方面,網絡刮擦是從網站提取特定數據的過程。它涉及解析網頁的HTML以刪除所需的數據。雖然網絡爬網是關於導航和索引的,但網絡刮擦是關於數據提取的。

>為什麼要使用node.js進行網絡爬行?

異步性質。它允許並發處理,這意味著您可以同時爬網多頁。這使其比同步執行的其他語言要快得多。此外,Node.js擁有一個豐富的生態系統,具有許多可以幫助網絡爬行的庫和工具,例如Phantomjs Horseman。 > Phantomjs Horseman是一個Node.js軟件包,可為使用Phantomjs自動化Web瀏覽器提供高級API。它允許您在網頁上執行操作,例如單擊鏈接,填寫表單和屏幕截圖。這使其成為網絡爬網的強大工具,因為它使您可以像人類用戶一樣與網頁進行交互。

> JavaScript渲染如何影響Web爬行? >

>我可以使用Web爬網來監視網站上的更改嗎? ,網絡爬行可用於監視網站上的更改。通過定期爬行網站並將當前狀態與以前的狀態進行比較,您可以檢測任何更改。這對於各種目的可能很有用,例如在電子商務網站上跟踪價格變化或監視新聞網站上的更新。

網絡爬行法律?

>

>網絡爬行的合法性取決於在包括您所處的管轄權以及您爬行的特定網站上的幾個因素上。一些網站明確允許Web在其robots.txt文件中爬行,而另一些網站則禁止Web爬網。重要的是要尊重網站的robots.txt文件,並且不要在短時間內用太多請求超載網站的服務器。

>

>我如何優化我的網絡爬行過程?是優化網絡爬行過程的幾種方法。一種方法是使用廣度優先搜索(BFS)算法,該算法可確保您在進入下一個深度級別之前,在一定深度爬網。另一種方法是根據頁面的相關性優先考慮爬網。例如,如果您要抓取電子商務網站,您可能想在博客文章之前爬網。 >是的,使用Phantomjs Horseman,您可以自動登錄網站的過程。這使您可以在登錄後訪問僅訪問的頁面。但是,您應該意識到這可能違反網站的服務條款。

我如何處理網絡爬網中的動態內容?

>處理動態內容在Web Crawling中可能具有挑戰性,作為傳統Web爬網僅解析網頁的靜態HTML。但是,使用Phantomjs Horseman之類的工具,您可以像人類用戶一樣渲染JavaScript並與動態內容進行交互。這使您可以從嚴重依賴JavaScript進行內容生成的網站上爬網和提取數據。 >

>如何阻止我的網絡爬行者被阻塞?一種方法是尊重網站的robots.txt文件,該文件提供了有關您允許爬網的哪些部分的指南。另一種方法是限制您將請求發送到網站的速率,以避免服務器超載。您也可以旋轉IP地址和用戶代理以避免被檢測為機器人。 >

以上是網絡與節點,phantomjs和騎手一起爬行的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn