欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

如何使用Node.js高效地從Web爬取數(shù)據(jù)

這篇文章主要介紹如何使用Node.js高效地從Web爬取數(shù)據(jù),文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供臨縣網(wǎng)站建設(shè)、臨縣做網(wǎng)站、臨縣網(wǎng)站設(shè)計、臨縣網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、臨縣企業(yè)網(wǎng)站模板建站服務(wù),十載臨縣做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。

由于Javascript有了巨大的改進(jìn),并且引入了稱為NodeJS的運行時,因此它已成為最流行和使用最廣泛的語言之一。 無論是Web應(yīng)用程序還是移動應(yīng)用程序,Javascript現(xiàn)在都具有正確的工具。本文講解怎樣用 Node.js 高效地從 Web 爬取數(shù)據(jù)。

前提條件

本文主要針對具有一定 JavaScript 經(jīng)驗的程序員。如果你對 Web 抓取有深刻的了解,但對 JavaScript 并不熟悉,那么本文仍然能夠?qū)δ阌兴鶐椭?/p>

  • ? 會 JavaScript

  • ? 會用 DevTools 提取元素選擇器

  • ? 會一些 ES6 (可選)

你將學(xué)到

通過本文你將學(xué)到:

  • 學(xué)到更多關(guān)于 Node.js 的東西

  • 用多個 HTTP 客戶端來幫助 Web 抓取的過程

  • 利用多個經(jīng)過實踐考驗過的庫來爬取 Web

了解 Node.js

Javascript 是一種簡單的現(xiàn)代編程語言,最初是為了向瀏覽器中的網(wǎng)頁添加動態(tài)效果。當(dāng)加載網(wǎng)站后,Javascript 代碼由瀏覽器的 Javascript 引擎運行。為了使 Javascript 與你的瀏覽器進(jìn)行交互,瀏覽器還提供了運行時環(huán)境(document、window等)。

這意味著 Javascript 不能直接與計算機(jī)資源交互或?qū)ζ溥M(jìn)行操作。例如在 Web 服務(wù)器中,服務(wù)器必須能夠與文件系統(tǒng)進(jìn)行交互,這樣才能讀寫文件。

Node.js 使 Javascript 不僅能夠運行在客戶端,而且還可以運行在服務(wù)器端。為了做到這一點,其創(chuàng)始人 Ryan Dahl 選擇了Google Chrome 瀏覽器的 v8 Javascript Engine,并將其嵌入到用 C++ 開發(fā)的 Node 程序中。所以 Node.js 是一個運行時環(huán)境,它允許 Javascript 代碼也能在服務(wù)器上運行。

與其他語言(例如 C 或 C++)通過多個線程來處理并發(fā)性相反,Node.js 利用單個主線程并并在事件循環(huán)的幫助下以非阻塞方式執(zhí)行任務(wù)。

要創(chuàng)建一個簡單的 Web 服務(wù)器非常簡單,如下所示:

const http = require('http');
const PORT = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, () => {
  console.log(`Server running at PORT:${port}/`);
});

如果你已安裝了 Node.js,可以試著運行上面的代碼。 Node.js 非常適合 I/O 密集型程序。

HTTP 客戶端:訪問 Web

HTTP 客戶端是能夠?qū)⒄埱蟀l(fā)送到服務(wù)器,然后接收服務(wù)器響應(yīng)的工具。下面提到的所有工具底的層都是用 HTTP 客戶端來訪問你要抓取的網(wǎng)站。

Request

Request 是 Javascript 生態(tài)中使用最廣泛的 HTTP 客戶端之一,但是 Request 庫的作者已正式聲明棄用了。不過這并不意味著它不可用了,相當(dāng)多的庫仍在使用它,并且非常好用。用 Request 發(fā)出 HTTP 請求是非常簡單的:

const request = require('request')
request('https://www.reddit.com/r/programming.json', function (
  error,
  response,
  body
) {
  console.error('error:', error)
  console.log('body:', body)
})

你可以在 Github 上找到 Request 庫,安裝它非常簡單。你還可以在 https://github.com/request/re... 找到棄用通知及其含義。

Axios

Axios 是基于 promise 的 HTTP 客戶端,可在瀏覽器和 Node.js 中運行。如果你用 Typescript,那么 axios 會為你覆蓋內(nèi)置類型。通過 Axios 發(fā)起 HTTP 請求非常簡單,默認(rèn)情況下它帶有 Promise 支持,而不是在 Request 中去使用回調(diào):

const axios = require('axios')

axios
    .get('https://www.reddit.com/r/programming.json')
    .then((response) => {
        console.log(response)
    })
    .catch((error) => {
        console.error(error)
    });

如果你喜歡 Promises API 的 async/await 語法糖,那么你也可以用,但是由于頂級 await 仍處于 stage 3 ,所以我們只好先用異步函數(shù)來代替:

async function getForum() {
    try {
        const response = await axios.get(
            'https://www.reddit.com/r/programming.json'
        )
        console.log(response)
    } catch (error) {
        console.error(error)
    }
}

你所要做的就是調(diào)用 getForum!可以在 https://github.com/axios/axios 上找到Axios庫。

Superagent

與 Axios 一樣,Superagent 是另一個強大的 HTTP 客戶端,它支持 Promise 和 async/await 語法糖。它具有像 Axios 這樣相當(dāng)簡單的 API,但是 Superagent 由于存在更多的依賴關(guān)系并且不那么流行。

用 promise、async/await 或回調(diào)向 Superagent 發(fā)出HTTP請求看起來像這樣:

const superagent = require("superagent")
const forumURL = "https://www.reddit.com/r/programming.json"

// callbacks
superagent
    .get(forumURL)
    .end((error, response) => {
        console.log(response)
    })

// promises
superagent
    .get(forumURL)
    .then((response) => {
        console.log(response)
    })
    .catch((error) => {
        console.error(error)
    })

// promises with async/await
async function getForum() {
    try {
        const response = await superagent.get(forumURL)
        console.log(response)
    } catch (error) {
        console.error(error)
    }
}

可以在 https://github.com/visionmedi... 找到 Superagent。

正則表達(dá)式:艱難的路

在沒有任何依賴性的情況下,最簡單的進(jìn)行網(wǎng)絡(luò)抓取的方法是,使用 HTTP 客戶端查詢網(wǎng)頁時,在收到的 HTML 字符串上使用一堆正則表達(dá)式。正則表達(dá)式不那么靈活,而且很多專業(yè)人士和業(yè)余愛好者都難以編寫正確的正則表達(dá)式。

讓我們試一試,假設(shè)其中有一個帶有用戶名的標(biāo)簽,我們需要該用戶名,這類似于你依賴正則表達(dá)式時必須執(zhí)行的操作

const htmlString = '<label>Username: John Doe</label>'
const result = htmlString.match(/<label>(.+)<\/label>/)

console.log(result[1], result[1].split(": ")[1])
// Username: John Doe, John Doe

在 Javascript 中,match()  通常返回一個數(shù)組,該數(shù)組包含與正則表達(dá)式匹配的所有內(nèi)容。第二個元素(在索引1中)將找到我們想要的 <label> 標(biāo)記的 textContentinnerHTML。但是結(jié)果中包含一些不需要的文本( “Username: “),必須將其刪除。

如你所見,對于一個非常簡單的用例,步驟和要做的工作都很多。這就是為什么應(yīng)該依賴 HTML 解析器的原因,我們將在后面討論。

Cheerio:用于遍歷 DOM 的核心 JQuery

Cheerio 是一個高效輕便的庫,它使你可以在服務(wù)器端使用 JQuery 的豐富而強大的 API。如果你以前用過 JQuery,那么將會對 Cheerio 感到很熟悉,它消除了 DOM 所有不一致和與瀏覽器相關(guān)的功能,并公開了一種有效的 API 來解析和操作 DOM。

const cheerio = require('cheerio')
const $ = cheerio.load('<h3 class="title">Hello world</h3>')

$('h3.title').text('Hello there!')
$('h3').addClass('welcome')

$.html()
// <h3 class="title welcome">Hello there!</h3>

如你所見,Cheerio 與 JQuery 用起來非常相似。

但是,盡管它的工作方式不同于網(wǎng)絡(luò)瀏覽器,也就這意味著它不能:

  • 渲染任何解析的或操縱 DOM 元素

  • 應(yīng)用 CSS 或加載外部資源

  • 執(zhí)行 JavaScript

因此,如果你嘗試爬取的網(wǎng)站或 Web 應(yīng)用是嚴(yán)重依賴 Javascript 的(例如“單頁應(yīng)用”),那么 Cheerio 并不是最佳選擇,你可能不得不依賴稍后討論的其他選項。

為了展示 Cheerio 的強大功能,我們將嘗試在 Reddit 中抓取 r/programming 論壇,嘗試獲取帖子名稱列表。

首先,通過運行以下命令來安裝 Cheerio 和 axios:npm install cheerio axios。

然后創(chuàng)建一個名為 crawler.js 的新文件,并復(fù)制粘貼以下代碼:

const axios = require('axios');
const cheerio = require('cheerio');

const getPostTitles = async () => {
    try {
        const { data } = await axios.get(
            'https://old.reddit.com/r/programming/'
        );
        const $ = cheerio.load(data);
        const postTitles = [];

        $('div > p.title > a').each((_idx, el) => {
            const postTitle = $(el).text()
            postTitles.push(postTitle)
        });

        return postTitles;
    } catch (error) {
        throw error;
    }
};

getPostTitles()
.then((postTitles) => console.log(postTitles));

getPostTitles() 是一個異步函數(shù),將對舊的 reddit 的 r/programming 論壇進(jìn)行爬取。首先,用帶有 axios HTTP 客戶端庫的簡單 HTTP GET 請求獲取網(wǎng)站的 HTML,然后用 cheerio.load() 函數(shù)將 html 數(shù)據(jù)輸入到 Cheerio 中。

然后在瀏覽器的 Dev Tools 幫助下,可以獲得可以定位所有列表項的選擇器。如果你使用過 JQuery,則必須非常熟悉 $('div> p.title> a')。這將得到所有帖子,因為你只希望單獨獲取每個帖子的標(biāo)題,所以必須遍歷每個帖子,這些操作是在 each() 函數(shù)的幫助下完成的。

要從每個標(biāo)題中提取文本,必須在 Cheerio 的幫助下獲取 DOM元素( el 指代當(dāng)前元素)。然后在每個元素上調(diào)用 text() 能夠為你提供文本。

現(xiàn)在,打開終端并運行 node crawler.js,然后你將看到大約存有標(biāo)題的數(shù)組,它會很長。盡管這是一個非常簡單的用例,但它展示了 Cheerio 提供的 API 的簡單性質(zhì)。

如果你的用例需要執(zhí)行 Javascript 并加載外部源,那么以下幾個選項將很有幫助。

JSDOM:Node 的 DOM

JSDOM 是在 Node.js 中使用的文檔對象模型的純 Javascript 實現(xiàn),如前所述,DOM 對 Node 不可用,但是 JSDOM 是最接近的。它或多或少地模仿了瀏覽器。

由于創(chuàng)建了 DOM,所以可以通過編程與要爬取的 Web 應(yīng)用或網(wǎng)站進(jìn)行交互,也可以模擬單擊按鈕。如果你熟悉 DOM 操作,那么使用 JSDOM 將會非常簡單。

const { JSDOM } = require('jsdom')
const { document } = new JSDOM(
    '<h3 class="title">Hello world</h3>'
).window
const heading = document.querySelector('.title')
heading.textContent = 'Hello there!'
heading.classList.add('welcome')

heading.innerHTML
// <h3 class="title welcome">Hello there!</h3>

代碼中用 JSDOM 創(chuàng)建一個 DOM,然后你可以用和操縱瀏覽器 DOM 相同的方法和屬性來操縱該 DOM。

為了演示如何用 JSDOM 與網(wǎng)站進(jìn)行交互,我們將獲得 Reddit r/programming 論壇的第一篇帖子并對其進(jìn)行投票,然后驗證該帖子是否已被投票。

首先運行以下命令來安裝 jsdom 和 axios:npm install jsdom axios

然后創(chuàng)建名為 crawler.js的文件,并復(fù)制粘貼以下代碼:

const { JSDOM } = require("jsdom")
const axios = require('axios')

const upvoteFirstPost = async () => {
  try {
    const { data } = await axios.get("https://old.reddit.com/r/programming/");
    const dom = new JSDOM(data, {
      runScripts: "dangerously",
      resources: "usable"
    });
    const { document } = dom.window;
    const firstPost = document.querySelector("div > div.midcol > div.arrow");
    firstPost.click();
    const isUpvoted = firstPost.classList.contains("upmod");
    const msg = isUpvoted
      ? "Post has been upvoted successfully!"
      : "The post has not been upvoted!";

    return msg;
  } catch (error) {
    throw error;
  }
};

upvoteFirstPost().then(msg => console.log(msg));

upvoteFirstPost() 是一個異步函數(shù),它將在 r/programming 中獲取第一個帖子,然后對其進(jìn)行投票。axios 發(fā)送 HTTP GET 請求獲取指定 URL 的HTML。然后通過先前獲取的 HTML 來創(chuàng)建新的 DOM。 JSDOM 構(gòu)造函數(shù)把HTML 作為第一個參數(shù),把 option 作為第二個參數(shù),已添加的 2 個 option 項執(zhí)行以下功能:

  • runScripts:設(shè)置為 dangerously 時允許執(zhí)行事件 handler 和任何 Javascript 代碼。如果你不清楚將要運行的腳本的安全性,則最好將 runScripts 設(shè)置為“outside-only”,這會把所有提供的 Javascript 規(guī)范附加到 “window” 對象,從而阻止在 inside 上執(zhí)行的任何腳本。

  • resources:設(shè)置為“usable”時,允許加載用 <script> 標(biāo)記聲明的任何外部腳本(例如:從 cdn 提取的 JQuery 庫)

創(chuàng)建 DOM 后,用相同的 DOM 方法得到第一篇文章的 upvote 按鈕,然后單擊。要驗證是否確實單擊了它,可以檢查 classList 中是否有一個名為 upmod 的類。如果存在于 classList 中,則返回一條消息。

打開終端并運行 node crawler.js,然后會看到一個整潔的字符串,該字符串將表明帖子是否被贊過。盡管這個例子很簡單,但你可以在這個基礎(chǔ)上構(gòu)建功能強大的東西,例如,一個圍繞特定用戶的帖子進(jìn)行投票的機(jī)器人。

如果你不喜歡缺乏表達(dá)能力的 JSDOM ,并且實踐中要依賴于許多此類操作,或者需要重新創(chuàng)建許多不同的 DOM,那么下面將是更好的選擇。

Puppeteer:無頭瀏覽器

顧名思義,Puppeteer 允許你以編程方式操縱瀏覽器,就像操縱木偶一樣。它通過為開發(fā)人員提供高級 API 來默認(rèn)控制無頭版本的 Chrome。

如何使用Node.js高效地從Web爬取數(shù)據(jù)

Puppeteer 比上述工具更有用,因為它可以使你像真正的人在與瀏覽器進(jìn)行交互一樣對網(wǎng)絡(luò)進(jìn)行爬取。這就具備了一些以前沒有的可能性:

  • 你可以獲取屏幕截圖或生成頁面 PDF。

  • 可以抓取單頁應(yīng)用并生成預(yù)渲染的內(nèi)容。

  • 自動執(zhí)行許多不同的用戶交互,例如鍵盤輸入、表單提交、導(dǎo)航等。

它還可以在 Web 爬取之外的其他任務(wù)中發(fā)揮重要作用,例如 UI 測試、輔助性能優(yōu)化等。

通常你會想要截取網(wǎng)站的屏幕截圖,也許是為了了解競爭對手的產(chǎn)品目錄,可以用 puppeteer 來做到。首先運行以下命令安裝 puppeteer,:npm install puppeteer

這將下載 Chromium 的 bundle 版本,根據(jù)操作系統(tǒng)的不同,該版本大約 180 MB 至 300 MB。如果你要禁用此功能。

讓我們嘗試在 Reddit 中獲取 r/programming 論壇的屏幕截圖和 PDF,創(chuàng)建一個名為 crawler.js的新文件,然后復(fù)制粘貼以下代碼:

const puppeteer = require('puppeteer')

async function getVisual() {
    try {
        const URL = 'https://www.reddit.com/r/programming/'
        const browser = await puppeteer.launch()
        const page = await browser.newPage()

        await page.goto(URL)
        await page.screenshot({ path: 'screenshot.png' })
        await page.pdf({ path: 'page.pdf' })

        await browser.close()
    } catch (error) {
        console.error(error)
    }
}

getVisual()

getVisual() 是一個異步函數(shù),它將獲 URL 變量中 url 對應(yīng)的屏幕截圖和 pdf。首先,通過 puppeteer.launch() 創(chuàng)建瀏覽器實例,然后創(chuàng)建一個新頁面??梢詫⒃擁撁嬉暈槌R?guī)瀏覽器中的選項卡。然后通過以 URL 為參數(shù)調(diào)用  page.goto() ,將先前創(chuàng)建的頁面定向到指定的 URL。最終,瀏覽器實例與頁面一起被銷毀。

完成操作并完成頁面加載后,將分別使用 page.screenshot() 和  page.pdf() 獲取屏幕截圖和 pdf。你也可以偵聽 javascript load 事件,然后執(zhí)行這些操作,在生產(chǎn)環(huán)境級別下強烈建議這樣做。

在終端上運行 node crawler.js  ,幾秒鐘后,你會注意到已經(jīng)創(chuàng)建了兩個文件,分別名為  screenshot.jpgpage.pdf。

Nightmare:Puppeteer 的替代者

Nightmare 是類似 Puppeteer 的高級瀏覽器自動化庫,該庫使用 Electron,但據(jù)說速度是其前身 PhantomJS 的兩倍。

如果你在某種程度上不喜歡 Puppeteer 或?qū)?Chromium 捆綁包的大小感到沮喪,那么 nightmare 是一個理想的選擇。首先,運行以下命令安裝 nightmare 庫:npm install nightmare

然后,一旦下載了 nightmare,我們將用它通過 Google 搜索引擎找到 ScrapingBee 的網(wǎng)站。創(chuàng)建一個名為crawler.js的文件,然后將以下代碼復(fù)制粘貼到其中:

const Nightmare = require('nightmare')
const nightmare = Nightmare()

nightmare
    .goto('https://www.google.com/')
    .type("input[title='Search']", 'ScrapingBee')
    .click("input[value='Google Search']")
    .wait('#rso > div:nth-child(1) > div > div > div.r > a')
    .evaluate(
        () =>
            document.querySelector(
                '#rso > div:nth-child(1) > div > div > div.r > a'
            ).href
    )
    .end()
    .then((link) => {
        console.log('Scraping Bee Web Link': link)
    })
    .catch((error) => {
        console.error('Search failed:', error)
    })

首先創(chuàng)建一個 Nighmare 實例,然后通過調(diào)用 goto() 將該實例定向到 Google 搜索引擎,加載后,使用其選擇器獲取搜索框,然后使用搜索框的值(輸入標(biāo)簽)更改為“ScrapingBee”。完成后,通過單擊 “Google搜索” 按鈕提交搜索表單。然后告訴 Nightmare 等到第一個鏈接加載完畢,一旦完成,它將使用 DOM 方法來獲取包含該鏈接的定位標(biāo)記的 href 屬性的值。

最后,完成所有操作后,鏈接將打印到控制臺。

總結(jié)

  • ? Node.js是 Javascript 在服務(wù)器端的運行時環(huán)境。由于事件循環(huán)機(jī)制,它具有“非阻塞”性質(zhì)。

  • ? HTTP客戶端(例如 Axios、Superagent 和 Request)用于將 HTTP 請求發(fā)送到服務(wù)器并接收響應(yīng)。

  • ? Cheerio把  JQuery 的優(yōu)點抽出來,在服務(wù)器端 進(jìn)行 Web 爬取是唯一的目的,但不執(zhí)行 Javascript 代碼。

  • ? JSDOM根據(jù)標(biāo)準(zhǔn) Javascript規(guī)范 從 HTML 字符串中創(chuàng)建一個 DOM,并允許你對其執(zhí)行DOM操作。

  • ? Puppeteerand Nightmare 是高級(high-level )瀏覽器自動化庫,可讓你以編程方式去操作 Web 應(yīng)用,就像真實的人正在與之交互一樣。

以上是“如何使用Node.js高效地從Web爬取數(shù)據(jù)”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

當(dāng)前文章:如何使用Node.js高效地從Web爬取數(shù)據(jù)
網(wǎng)頁URL:http://chinadenli.net/article12/gohpgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、App設(shè)計、微信公眾號、做網(wǎng)站自適應(yīng)網(wǎng)站、虛擬主機(jī)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
欧美丰满人妻少妇精品| 好东西一起分享老鸭窝| 少妇淫真视频一区二区| 日韩在线免费看中文字幕| 色丁香之五月婷婷开心| 国产内射一级二级三级| 成人精品日韩专区在线观看 | 色哟哟国产精品免费视频| 久久免费精品拍拍一区二区 | 国产精品99一区二区三区| 国内精品伊人久久久av高清| 午夜亚洲精品理论片在线观看| 欧美午夜视频免费观看| 99久久精品午夜一区二| 粉嫩国产一区二区三区在线| 免费观看潮喷到高潮大叫| 国产一区一一一区麻豆| 国产在线不卡中文字幕| 欧美日韩乱码一区二区三区| 国产a天堂一区二区专区| 国产极品粉嫩尤物一区二区| 老熟女露脸一二三四区| 国内外激情免费在线视频| 国产水滴盗摄一区二区| 欧美黑人在线精品极品| 日韩精品一区二区三区含羞含羞草| 亚洲中文字幕在线乱码av| 亚洲第一区二区三区女厕偷拍| 亚洲伦片免费偷拍一区| 小黄片大全欧美一区二区| 国产在线一区二区免费| 少妇人妻无一区二区三区| 欧美性猛交内射老熟妇| 亚洲精品成人综合色在线| 久久这里只有精品中文字幕| 午夜福利在线观看免费| 男人操女人下面国产剧情| 亚洲国产成人精品一区刚刚| 东京热男人的天堂久久综合| 亚洲国产av在线观看一区| 少妇福利视频一区二区|