爬虫新姿势——使用Chrome Devtools写一个小说爬虫

目前,绝大部分的爬虫教程都是基于Python和Node.js。其实,只要有Chrome浏览器,使用Chrome F12打开的的Devtools就能随时随地轻轻松松写一个爬虫,完全不用装其它语言环境。今天就介绍一下只使用Chrome Devtools来爬取网站www.biqudu.com/31_31729/小说并保存为文本文件的爬虫。

如何在Chrome Devtools里面写爬虫代码

Devtools提供了Snippets功能让我们可以在这里写JavaScript代码,步骤参考下图:

步骤说明

  1. 打开source标签

  2. 左侧选择Snippets标签

  3. 点击New Snippets新建一个Snippets

  4. 开始写代码

  5. 点击运行代码

  6. 查看控制台输出


准备爬虫工具函数

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。

完整代码运行步骤

  1. Chrome浏览器打开小说主页如:www.biqudu.com/31_31729/

  2. 在小说主页页面打开Devtools 新建snippets并将下面的完整代码粘贴进去

  3. 点击运行代码开始爬取小说

    (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);//并发送设成6
    
         q.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();

    }());

相关推荐
❀͜͡傀儡师几秒前
docker部署Docker Compose文件Web管理工具Dockman
java·前端·docker·dockman
赫凯2 分钟前
【强化学习】第三章 马尔可夫决策过程
python·算法
Daily Mirror2 分钟前
Day42 Dataset和Dataloader
python
智航GIS3 分钟前
1.2 python及pycharm的安装
开发语言·python·pycharm
froginwe118 分钟前
Lua 字符串处理指南
开发语言
式5168 分钟前
大模型学习基础(六) 强化学习(Reinforcement Learning,RL)初步1.3
学习
kszlgy10 分钟前
Day38 模型可视化与推理
python
k***921614 分钟前
list 迭代器:C++ 容器封装的 “行为统一” 艺术
java·开发语言·数据结构·c++·算法·list
阿恩.77014 分钟前
材料工程科技期刊征稿:快速发表,知网、维普检索!
经验分享·笔记·考研·网络安全·数学建模·能源·制造
karshey16 分钟前
【前端】sort:js按照固定顺序排序
开发语言·前端·javascript