Node.jsでHTMLを取得してparseして必要なデータを取得する
2021/05/16
はじめに
スクレイピングをする機会が多いのでメモとして残す。
htmlを取得する
url
を渡して取得する。コメントを外せば保存ができるようにしてある。
エラー対策してないのは割愛
const get = (url) =>{
return new Promise((resolve, reject)=>{
request.get({
uri: url,
headers: {'Content-type': 'text/html;'},
}, function(err, req, data){
if(req.statusCode == 200){
resolve(data)
//fs.writeFileSync(path.resolve(__dirname,`./temp-${Date.now()}.html`), data);
}
console.log("complate:",url);
resolve("");
});
})
}
htmlをパースする
JSDOM
を使ってHTMLをパースして window
から色々取れるようになる。javascript
で描画されるものは対応してないっぽいので、ちょっと処理が重くなっちゃうけど Headless Chrome
とかの方が良いかも。試してはない document.addEventListener("DOMContentLoaded",()=>{...})
みたいに取得できたら良いかなと思おうけど非同期処理を入れる必要があるかな。runScripts: "dangerously"
プロパティを設定すると js
などが走るっぽい。resources: "usable"
を設定することで外部リソースの利用を許可する。
const htmlParse = (htmlText) =>{
try{
const dom = new JSDOM(htmlText,{
runScripts: "dangerously",
resources: "usable"
});
// get element
const text = dom.window.document.title;
console.log(`text:`,text);
}catch (e){
console.error(e)
}
}
全体
url.txt
からUrl群を取得してUrlからHTMLを取得する。
const fs = require('fs');
const glob = require('glob');
const request = require('request');
const path = require('path');
const { JSDOM } = require('jsdom')
const urls = fs
.readFileSync(
path.resolve(__dirname,"url.txt"),'utf8'
)
.split('\n')
.filter(t=>t.length > 0);
const get = (url) =>{
return new Promise((resolve, reject)=>{
request.get({
uri: url,
headers: {'Content-type': 'text/html;'},
}, function(err, req, data){
if(req.statusCode == 200){
resolve(data)
//fs.writeFileSync(path.resolve(__dirname,`./temp-${Date.now()}.html`), data);
}
console.log("complate:",url);
resolve("");
});
})
}
const htmlParse = (htmlText) =>{
try{
const dom = new JSDOM(htmlText,{
runScripts: "dangerously",
resources: "usable"
});
// get element
setTimeout(()=>{
const text = dom.window.document.title;
console.log(`text:`,text);
},1000);
}catch (e){
console.error(e)
}
}
Promise.all(urls.map(url=>get(url))).then((htmls)=>{
htmls.forEach((html) => {
htmlParse(html)
});
});
// glob.sync(path.resolve(__dirname,`./temp-*.html`)).forEach((p)=>{
// fs.unlinkSync(p);
// });
終わりに
JSDOM
にfromURL()
というメソッドがあるのでHTMLファイルとして保存しない場合request
が必要ないかも。fromFile()
メソッドもあるので保存したHTMLファイルから再開もfs
を使わないでできそう。
JSDOM.fromURL("https://example.com/", options).then(dom => {
console.log(dom.serialize());
});
window.matchMedia
がない。Headless Chrome
でいいかな…。