某个周日晚上偶然发现了《火星异种》这部漫画,便在网上在线看了起来。在看的过程中图片加载很慢,而且有时候还不小心点到广告,大大延缓了我看的进度。后来想到能不能把先把漫画全部抓取到本地再去看。

  经过一段时间的研究还是有所收获:成功在风之动漫网站上抓取了《火星异种》,以及在腾讯动漫上抓取了《海贼王》。一般来说,抓取网页内容有两种形式:一是静态资源,即网站内容在第一时间就全部呈现在网页上;另一种是动态资源,即网站内容随后通过用户交互,如:操作滚动条等,异步的更新。对于第一种形式,直接通过发送 request 请求并解析返回结果即可;对于第二种形式,可以通过 PhantomJS 模拟浏览器访问,并通过写代码模拟用户交互行为,最终拿到数据。

1. 静态资源抓取 (代码地址:Node.jsPython)

分析阶段:

  1. 打开《火星异种》漫画首页 ,发现 “http://www.fzdm.com/manhua/47/” 有数字 “47”,将数字 “47” 改成 “48” 后发现是《吞噬人间》漫画首页,于是我们知道了这个数字用来标识不同漫画

  2. 随机进入 48 话和 86 话,发现连接分别为“http://www.fzdm.com/manhua/47/48/” 和 “http://www.fzdm.com/manhua/47/86/”,于是我们知道了每一话的连接地址(注:实际上第001话的地址为 “http://www.fzdm.com/manhua/47/001/”,但由于当时已经看到 40 多话了,代码没有对这一块进行特殊处理

  3. 随机进入 50 话,随机查看不同页的 URL 后发现 URL 的形式为 “http://www.fzdm.com/manhua/47/50/index_*.html” 其中 * 和当前页码对应

4. 查看每一页的漫画图片元素发现,<img> 元素的 id = "mhpic",因此可以轻松获取到漫画图片的地址

  5. 最后只需要发送请求到漫画图片所在的地址,并将图片数据保存在本地即可

注意事项:

  1. 需要记录当前已抓取到哪一话,也就是记录当前抓取的状态。当需要抓取的内容特别长,不能一次性抓完时,保存上一次抓取的断点十分必要,同时也是为了在抓取的过程中出现错误后不用每次从头抓取

  2. 最好在抓取之前先检测改文件是否存在,不存在才发送请求。这是为了当程序中出现bug导致已抓取的页面不全时,不用再重复抓取已经存在的图片

  3. 添加重试机制,在一定时间内访问同一个站点次数太多,可能会出现服务拒绝之类的错误。调节好访问频率,出错后每隔一段时间进行重试即可。

Bonus:

  在查看网页源码的时候发现,当前页面除了加载当前页的漫画图片资源外,还会加载下一话的图片资源,并在当前页隐藏。这样查看下一页的时候就能直接从缓存中读取数据。

2. 动态资源抓取 (代码地址:Node.js)

分析阶段:

  1. 打开《海贼王》漫画首页,随机打开 857 和 858 话,地址分别为 “http://ac.qq.com/ComicView/index/id/505430/cid/874” 和 “http://ac.qq.com/ComicView/index/id/505430/cid/875”。发现虽然 URL 是连贯的,但和当前话数字对应不上。打开第一话发现地址是 “http://ac.qq.com/ComicView/index/id/505430/cid/1”,于是猜测中间有些 URL 可能失效了,需要再代码里做好容错 (无论在什么情况下最好都做好容错)。

  2. 随机打开 857 话,发现漫画图片是随着往下滚动动态加载。查看网页源码发现,未加载漫画图片的地方是用地址为“http://ac.gtimg.com/media/images/pixel.gif”的图片占位。于是不能简单的通过单次请求来获取漫画图片地址。需要使用 PhantomJS PhantomJS for Node等工具来模拟浏览器访问,并通过代码模拟用户交互行为,最终获取数据

  3. 通过 setTimeout 改变 scrollTop 来模拟下拉滚动条,滚动到页面底部后,查看页面有效 img 标签的数量看是否等于当前话的页数,否的话继续模拟用户从头下拉滚动条。

注意事项:

  1. PhantomJS 代码是在隔离沙箱中运行,不能使用 Node 代码环境下的全局变量之类的,可以通过 “onConsoleMessage” 事件来与 Node 环境交互。

Python 和 Node 对比使用体验

  由于对 Node 比较熟,所以是先写好 Node 版本,有时间的话在用 Python 写一遍。在写的过程中发现,Node 的回调写法用在这样的场景不太方便,但如果用上 ES7 的 Async/Await 的话,写起来就方便很多了;但用 Node 的优势是解析网页数据十分方便,就像在浏览器端进行 DOM 操作一样。使用 Python 的优势是同步的写法,缺点是解析网页数据不方便。

  虽然 Node 的异步写法用在这种场景下很不方便,但也正因为异步的关系,可以用一个进程一次性抓取好几个不同的漫画,实现类似多线程的效果。

Node.js/Python爬取网上漫画的更多相关文章

  1. Node.js 爬虫爬取电影信息

    Node.js 爬虫爬取电影信息 我的CSDN地址:https://blog.csdn.net/weixin_45580251/article/details/107669713 爬取的是1905电影 ...

  2. Python爬取网上车市[http://www.cheshi.com/]的数据

    #coding:utf8 #爬取网上车市[http://www.cheshi.com/]的数据 import requests, json, time, re, os, sys, time,urlli ...

  3. 养只爬虫当宠物(Node.js爬虫爬取58同城租房信息)

    先上一个源代码吧. https://github.com/answershuto/Rental 欢迎指导交流. 效果图 搭建Node.js环境及启动服务 安装node以及npm,用express模块启 ...

  4. node.js爬虫爬取拉勾网职位信息

    简介 用node.js写了一个简单的小爬虫,用来爬取拉勾网上的招聘信息,共爬取了北京.上海.广州.深圳.杭州.西安.成都7个城市的数据,分别以前端.PHP.java.c++.python.Androi ...

  5. Node.js爬虫-爬取慕课网课程信息

    第一次学习Node.js爬虫,所以这时一个简单的爬虫,Node.js的好处就是可以并发的执行 这个爬虫主要就是获取慕课网的课程信息,并把获得的信息存储到一个文件中,其中要用到cheerio库,它可以让 ...

  6. 手把手教你用Node.js爬虫爬取网站数据

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 开始之前请先确保自己安装了Node.js环境,还没有安装的的童鞋请自行百度 ...

  7. node js 爬虫爬取静态页面,

    先打一个简单的通用框子 //根据爬取网页的协议 引入对应的协议, http||https var http = require('https'); //引入cheerio 简单点讲就是node中的jq ...

  8. 使用node.js如何爬取网站数据

    数据库又不会弄,只能扒扒别人的数据了. 搭建环境: (1).创建一个文件夹,进入并初始化一个package.json文件.  npm init -y (2).安装相关依赖:  npm install ...

  9. python爬取哦漫画

    import requests from lxml import etree from bs4 import BeautifulSoup import os from selenium import ...

随机推荐

  1. sql server内存使用情况

    查看Sql Server 数据库的内存使用情况 转自:https://www.cnblogs.com/wanghao4023030/p/8299478.html    DBCC MemoryStatu ...

  2. tensorflow 中 name_scope 及 variable_scope 的异同

    Let's begin by a short introduction to variable sharing. It is a mechanism in TensorFlow that allows ...

  3. Django相关介绍

    先认识一下MVC框架 MVC的框架模式,即模型M,视图V和控制器C.他们之间以一种插件似的,松耦合的方式连接在一起. Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在 ...

  4. mysql忽略一些错误代码

    模拟的故障,在从库中新建一个库,然后主库新建一个与从库相同名字的库,然后进入下面的show Mysql从库复制故障解决 当show slave status:报错 slave_io_running:y ...

  5. 在python中如何使用多进制数字

    我们在python中,除十进制外还可以使用二进制.八进制和十六进制 1.二进制数字由0和1组成,我们使用0b或0B前缀表示二进制数 2.使用bin()函数将一个数字转换为它的二进制形式 print(b ...

  6. (转)Nginx反向代理设置 从80端口转向其他端口

    from :http://www.cnblogs.com/wuyou/p/3455381.html Nginx反向代理设置 从80端口转向其他端口   反向代理(Reverse Proxy)方式是指以 ...

  7. [笔记]Go语言实现同一结构体适配多种消息源

    问题: 提供天气信息的网站有很多,每家的数据及格式都不同,为了适配各种不同的天气接口,写了如下程序. 代码如下: package main import ( "encoding/json&q ...

  8. Android 6.0 Kotlin 蓝牙BLE扫描

    package com.arci.myapplication import android.os.Bundleimport android.support.design.widget.Snackbar ...

  9. iOS 和服务端交互 数据加密策略

    总体逻辑: 客户端:对称加密数据,上传...回执对称解密 同理服务端:获取上传数据 对称解密 ...下发:对称加密 当且仅当登录接口和 拉新(更新nonce 和 key的接口)是对称加密上传 非对称解 ...

  10. Python读写改Excel的方法

    (注:本文部分内容摘自互联网,由于作者水平有限,不足之处,还望留言指正.) 面对疾风吧. 回首往昔,更进一步. 且随疾风前行,身后一许流星. 正文: 数据处理是Python的一大应用场景,而 Exce ...