目前,绝大部分的爬虫教程都是基于Python和Node.js。其实,只要有Chrome浏览器,使用Chrome F12打开的的Devtools就能随时随地轻轻松松写一个爬虫,完全不用装其它语言环境。今天就介绍一下只使用Chrome Devtools来爬取网站www.biqudu.com/31_31729/小说并保存为文本文件的爬虫。
如何在Chrome Devtools里面写爬虫代码
Devtools提供了Snippets功能让我们可以在这里写JavaScript代码,步骤参考下图:
步骤说明
-
打开source标签
-
左侧选择Snippets标签
-
点击New Snippets新建一个Snippets
-
开始写代码
-
点击运行代码
-
查看控制台输出
准备爬虫工具函数
1.加载第三方库
根据Url加载一个第三方库,可以用这个函数加载jquery,underscore等工具库,加载完成后就可以在代码中使用这些库了,本例中使用这个函数加载async异步并发控制库。
async function loadLibrary(url) {return new Promise((resolve, reject) => {let script = document.createElement('script');script.onload = resolve;script.onerror = reject;script.src = url;document.body.appendChild(script);});
}
2.下载文件到本地
将string下载到文本文件
function saveFile(string, fileName) {var a = document.createElement('a');a.download = fileName;var blob = new Blob([string], {type: 'text/plain'});a.href = window.URL.createObjectURL(blob);a.click();
}
3.下载HTML
使用了Fetch api,根据url下载一个html文本文件并转换成DOM元素后返回,返回的元素具有DOM api,例如 querySelector,方便对节点的提取和分析。
async function getHtml(url) {let response = await fetch(url);let htmlText = await response.text();let html = document.createElement('html');html.innerHTML = htmlText;return html;
}
准备爬虫业务函数
1.获取小说的所有章节信息
分析小说主页www.biqudu.com/31_31729/,
通过document.querySelectorAll('#list dd a')
可以获取包含所有章节名称和链接的a标签元素。
async function getDirectory(url) {let page = await getHtml(url);let directory = Array.from(page.querySelectorAll('#list dd a'));//去除顶部最新12个章节return directory.slice(12);
}
2.获取一个章节的内容
分析小说章节 www.biqudu.com/31_31729/21…,章节内容位于ID为content
的DIV元素中
async function getSection({ href, innerText: title }) {console.log(`开始获取 ${title}`);let html = await getHtml(href);let content = html.querySelector('#content');Array.from(content.querySelectorAll('script')).forEach(scriptTag => content.removeChild(scriptTag));var text = title + '\r\n' + content.innerText + '\r\n';return text;
}
完整代码
因为小说有几百几千章节,不可能一个一个章节下载,那样速度太慢了。也不能一下子全下载。所以
爬取时使用了async异步并发控制库(这个async和async function里面的async只是名字一样而已),并发数量为6,设置大了也没用因为Chrome浏览器对同一域名下的同时请求数量是6。
完整代码运行步骤
-
Chrome浏览器打开小说主页如:www.biqudu.com/31_31729/
-
在小说主页页面打开Devtools 新建snippets并将下面的完整代码粘贴进去
-
点击运行代码开始爬取小说
(async function () {// https://www.biqudu.com/31_31729/async function loadLibrary(url) {return new Promise((resolve, reject) => {let script = document.createElement('script');script.onload = resolve;script.onerror = reject;script.src = url;document.body.appendChild(script);});}function saveFile(string, fileName) {var a = document.createElement('a');a.download = fileName;var blob = new Blob([string], {type: 'text/plain'});a.href = window.URL.createObjectURL(blob);a.click();}async function getHtml(url) {let response = await fetch(url);let htmlText = await response.text();let html = document.createElement('html');html.innerHTML = htmlText;return html;}async function getDirectory(url) {let page = await getHtml(url);let directory = Array.from(page.querySelectorAll('#list dd a'));//去除顶部最新12个章节return directory.slice(12);}async function getSection({ href, innerText: title }) {console.log(`开始获取 ${title}`);let html = await getHtml(href);let content = html.querySelector('#content');Array.from(content.querySelectorAll('script')).forEach(scriptTag => content.removeChild(scriptTag));var text = title + '\r\n' + content.innerText + '\r\n';return text;}async function run() {let asyncLibUrl = 'https://cdn.bootcss.com/async/2.1.4/async.js';await loadLibrary(asyncLibUrl);let directory = await getDirectory(location.href);let q = window.async.queue(async function (section, taskDone) {try {section.text = await getSection(section);} catch (e) {console.error(e);section.text = "章节下载失败:" + e;} finally {taskDone();}}, 6);//并发送设成6q.drain = function () {let name = document.querySelector('#maininfo h1').innerText + '.txt';console.log(`小说《${name}》下载完成`);let content = "";directory.forEach(function ({ text }) {content += text;});saveFile(content, name);}q.push(directory);}await run();}());