摘要:全局安裝目前版本,這個版本不再需要使用命令了?,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
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗,增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:毫無疑問,設(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è)計...
摘要:在服務(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...
閱讀 893·2021-11-15 11:38
閱讀 2526·2021-09-08 09:45
閱讀 2828·2021-09-04 16:48
閱讀 2574·2019-08-30 15:54
閱讀 941·2019-08-30 13:57
閱讀 1629·2019-08-29 15:39
閱讀 506·2019-08-29 12:46
閱讀 3531·2019-08-26 13:39