成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用TypeScript開發(fā)爬蟲程序

CocoaChina / 1453人閱讀

摘要:全局安裝目前版本,這個版本不再需要使用命令了?,F(xiàn)在嘗試深入抓取文章內(nèi)容可以發(fā)現(xiàn)因為訪問服務(wù)器太迅猛,導(dǎo)致出現(xiàn)很多次錯誤。解決添加文件修改文件為修改文件為觀察輸出可以看到,程序?qū)崿F(xiàn)了隔一秒再請求下一個內(nèi)容頁。

全局安裝typescript:

npm install -g typescript

目前版本2.0.3,這個版本不再需要使用typings命令了。但是vscode捆綁的版本是1.8的,需要一些配置工作,看本文的處理辦法。

測試tsc命令:

tsc

創(chuàng)建要寫的程序項目文件夾:

mkdir test-typescript-spider

進(jìn)入該文件夾:

cd test-typescript-spider

初始化項目:

npm init

安裝superagent和cheerio模塊:

npm i --save superagent cheerio

安裝對應(yīng)的類型聲明模塊:

npm i -s @types/superagent --save
npm i -s @types/cheerio --save

安裝項目內(nèi)的typescript(必須走這一步):

npm i --save typescript

用vscode打開項目文件夾。在該文件夾下創(chuàng)建tsconfig.json文件,并復(fù)制以下配置代碼進(jìn)去:

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "noEmitOnError": true,
        "noImplicitAny": true,
        "experimentalDecorators": true,
        "sourceMap": false,
     // "sourceRoot": "./",
        "outDir": "./out"
    },
    "exclude": [
        "node_modules"
    ]
}

在vscode打開“文件”-“首選項”-“工作區(qū)設(shè)置”
在settings.json中加入(如果不做這個配置,vscode會在打開項目的時候提示選擇哪個版本的typescript):

{
   "typescript.tsdk": "node_modules/typescript/lib"
}

創(chuàng)建api.ts文件,復(fù)制以下代碼進(jìn)去:

import superagent = require("superagent");
import cheerio = require("cheerio");

export const remote_get = function(url: string) {

    const promise = new Promise(function (resolve, reject) {
        superagent.get(url)
            .end(function (err, res) {
                if (!err) {
                    resolve(res);
                } else {
                    console.log(err)
                    reject(err);
                }
            });
    });
    return promise;
}

創(chuàng)建app.ts文件,書寫測試代碼:

import api = require("./api");
const go = async () => {
    let res = await api.remote_get("http://www.baidu.com/");
    console.log(res.text);
}
go();

執(zhí)行命令:

tsc

然后:

node out/app

觀察輸出是否正確。

現(xiàn)在嘗試抓取http://cnodejs.org/的第一頁文章鏈接。
修改app.ts文件,代碼如下:

import api = require("./api");
import cheerio = require("cheerio");

const go = async () => {
    const res = await api.remote_get("http://cnodejs.org/");
    const $ = cheerio.load(res.text);
    let urls: string[] = [];
    let titles: string[] = [];
    $(".topic_title_wrapper").each((index, element) => {
        titles.push($(element).find(".topic_title").first().text().trim());
        urls.push("http://cnodejs.org/" + $(element).find(".topic_title").first().attr("href"));
    })
    console.log(titles, urls);
}
go();

觀察輸出,文章的標(biāo)題和鏈接都已獲取到了。

現(xiàn)在嘗試深入抓取文章內(nèi)容

import api = require("./api");
import cheerio = require("cheerio");

const go = async () => {
    const res = await api.remote_get("http://cnodejs.org/");
    const $ = cheerio.load(res.text);
    $(".topic_title_wrapper").each(async (index, element) => {
        let url = ("http://cnodejs.org" + $(element).find(".topic_title").first().attr("href"));
        const res_content = await api.remote_get(url);
        const $_content = cheerio.load(res_content.text);
        console.log($_content(".topic_content").first().text());
    })

}
go();

可以發(fā)現(xiàn)因為訪問服務(wù)器太迅猛,導(dǎo)致出現(xiàn)很多次503錯誤。
解決:
添加helper.ts文件:

export const wait_seconds = function (senconds: number) {
    return new Promise(resolve => setTimeout(resolve, senconds * 1000));
}

修改api.ts文件為:

import superagent = require("superagent");
import cheerio = require("cheerio");

export const get_index_urls = function () {
    const res = await remote_get("http://cnodejs.org/");
    const $ = cheerio.load(res.text);
    let urls: string[] = [];
    $(".topic_title_wrapper").each(async (index, element) => {
        urls.push("http://cnodejs.org" + $(element).find(".topic_title").first().attr("href"));
    });
    return urls;
}
export const get_content = async function (url: string) {
    const res = await remote_get(url);
    const $ = cheerio.load(res.text);
    return $(".topic_content").first().text();
}

export const remote_get = function (url: string) {

    const promise = new Promise(function (resolve, reject) {

        superagent.get(url)
            .end(function (err, res) {
                if (!err) {
                    resolve(res);
                } else {
                    console.log(err)
                    reject(err);
                }
            });
    });
    return promise;
}

修改app.ts文件為:

import api = require("./api");
import helper = require("./helper");
import cheerio = require("cheerio");

const go = async () => {
    let urls = await api.get_index_urls();
    for (let i = 0; i < urls.length; i++) {
        await helper.wait_seconds(1);
        let text = await api.get_content(urls[i]);
        console.log(text);
    }
}
go();

觀察輸出可以看到,程序?qū)崿F(xiàn)了隔一秒再請求下一個內(nèi)容頁。

現(xiàn)在嘗試把抓取到的東西存到數(shù)據(jù)庫中。
安裝mongoose模塊:

npm i mongoose --save
npm i -s @types/mongoose --save

然后建立Scheme。先創(chuàng)建models文件夾:

mkdir models

在models文件夾下創(chuàng)建index.ts:

import * as mongoose from "mongoose";

mongoose.connect("mongodb://127.0.0.1/cnodejs_data", {
    server: { poolSize: 20 }
}, function (err) {
    if (err) {
        process.exit(1);
    }
});

// models
export const Article = require("./article");

在models文件夾下創(chuàng)建IArticle.ts:

interface IArticle {
    title: String;
    url: String;
    text: String;
}
export = IArticle;

在models文件夾下創(chuàng)建Article.ts:

import mongoose = require("mongoose");
import IArticle = require("./IArticle");
interface IArticleModel extends IArticle, mongoose.Document { }

const ArticleSchema = new mongoose.Schema({
    title: { type: String },
    url: { type: String },
    text: { type: String },
});

const Article = mongoose.model("Article", ArticleSchema);
export = Article;

修改api.ts為:

import superagent = require("superagent");
import cheerio = require("cheerio");
import models = require("./models");
const Article = models.Article;

export const get_index_urls = async function () {
    const res = await remote_get("http://cnodejs.org/");

    const $ = cheerio.load(res.text);
    let urls: string[] = [];
    $(".topic_title_wrapper").each((index, element) => {
        urls.push("http://cnodejs.org" + $(element).find(".topic_title").first().attr("href"));
    });
    return urls;

}
export const fetch_content = async function (url: string) {
    const res = await remote_get(url);

    const $ = cheerio.load(res.text);
    let article = new Article();
    article.text = $(".topic_content").first().text();
    article.title = $(".topic_full_title").first().text().replace("置頂", "").replace("精華", "").trim();
    article.url = url;
    console.log("獲取成功:" + article.title);
    article.save();

}
export const remote_get = function (url: string) {

    return new Promise((resolve, reject) => {
        superagent.get(url)
            .end(function (err, res) {
                if (!err) {
                    resolve(res);
                } else {
                    reject(err);
                }
            });
    });
}

修改app.ts為:

import api = require("./api");
import helper = require("./helper");
import cheerio = require("cheerio");

(async () => {

    try {
        let urls = await api.get_index_urls();
        for (let i = 0; i < urls.length; i++) {
            await helper.wait_seconds(1);
            await api.fetch_content(urls[i]);
        }
    } catch (err) {
        console.log(err);
    }

    console.log("完畢!");

})();

執(zhí)行

tsc
node out/app

觀察輸出,并去數(shù)據(jù)庫檢查一下
可以發(fā)現(xiàn)入庫成功了!

補(bǔ)充:remote_get方法的改進(jìn)版,實現(xiàn)錯誤重試和加入代理服務(wù)器.
放棄了superagent庫,用的request庫,僅供參考:

//config.retries = 3;
let current_retry = config.retries || 0;
export const remote_get = async function (url: string, proxy?: string) {
    //每次請求都先稍等一下
    await wait_seconds(2);
    if (!proxy) {
        proxy = "";
    }
    const promise = new Promise(function (resolve, reject) {
        console.log("get: " + url + ",  using proxy: " + proxy);
        let options: request.CoreOptions = {
            headers: {
                "Cookie": "",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
                "Referer": "https://www.baidu.com/"
            },
            encoding: "utf-8",
            method: "GET",
            proxy: proxy,
            timeout: 3000,
        }
        request(url, options, async function (err, response, body) {
            console.log("got:" + url);
            if (!err) {
                body = body.toString();
                current_retry = config.retries || 0;
                console.log("bytes:" + body.length);
                resolve(body);
            } else {
                console.log(err);
                if (current_retry <= 0) {
                    current_retry = config.retries || 0;
                    reject(err);
                } else {
                    console.log("retry...(" + current_retry + ")")
                    current_retry--;
                    try {
                        let body = await remote_get(url, proxy);
                        resolve(body);
                    } catch (e) {
                        reject(e);
                    }
                }
            }
        });
    });
    return promise;
}

另外,IArticle.ts和Article.ts合并為一個文件,可能更好,可以參考我另一個model的寫法:

import mongoose = require("mongoose");

interface IProxyModel {
    uri: string;
    ip: string;
    port:string;
    info:string;
}
export interface IProxy extends IProxyModel, mongoose.Document { }

const ProxySchema = new mongoose.Schema({
    uri: { type: String },//
    ip: { type: String },//
    port: { type: String },//
    info: { type: String },//
});
export const Proxy = mongoose.model("Proxy", ProxySchema);

導(dǎo)入的時候這么寫就行了:

import { IProxy, Proxy } from "./models";

其中Proxy可以用來做new、find、where之類的操作:

let x = new Proxy();
let xx = await Proxy.find({});
let xxx = await Proxy.where("aaa",123).exec();

而IProxy用于實體對象的傳遞,例如

function xxx(p:IProxy){
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80709.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    caspar 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    nihao 評論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來學(xué)習(xí)一門新的編程語言吧!

    摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...

    Drummor 評論0 收藏0
  • 前端窩 - 收藏集 - 掘金

    摘要:毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的設(shè)計模式使代碼編寫真正工程化設(shè)計模小書前端掘金這是一本關(guān)于的小書。 JavaScript 常見設(shè)計模式解析 - 掘金設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的;設(shè)計...

    李文鵬 評論0 收藏0
  • Angular開發(fā)實踐(六):服務(wù)端渲染

    摘要:在服務(wù)端渲染方面提供一套前后端同構(gòu)解決方案,它就是統(tǒng)一平臺,一項在服務(wù)端運行應(yīng)用的技術(shù)。這些著陸頁是純,并且即使被禁用了也能顯示。它會把客戶端請求轉(zhuǎn)換成服務(wù)端渲染的頁面。它是服務(wù)端渲染器和你的應(yīng)用之間的橋梁。 Angular Universal Angular在服務(wù)端渲染方面提供一套前后端同構(gòu)解決方案,它就是 Angular Universal(統(tǒng)一平臺),一項在服務(wù)端運行 Angul...

    Eirunye 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<