本文将介绍写爬虫的思路以及提供一个具体的实现。需要依赖的工具有chrome浏览器和Node.js v12。
以商品 https://item.taobao.com/item.htm?id=555217237330 为例,我们需要爬取的是宝贝详情
tab下的所有图片。

爬虫的原理
爬虫是通过模拟用户访问给定的网站,执行某些操作或提取网站内容的程序。
爬取的思路
检查需要被爬取的内容所在dom节点的特征
根据特征搜索网页源码并定位相关内容
如果定位不到,在浏览器控制台进行全局搜索并通过Network Tab来过滤
思路实践
使用chrome浏览器打开 https://item.taobao.com/item.htm?id=555217237330。
我们右键一个待爬取的图片,检查元素,可以在chrome中看到如下显示:

先复制图片的链接,打开网页源码,在源码中进行搜索:

发现源码中并没有该图片地址,说明图片是通过脚本异步加载进来而不是和html页面一起返回的。
我们再通过检查元素,发现图片的父节点有个id J_DivItemDesc
, 有经验的开发者会想到,脚本是通过这个id来定位图片容器的。所以我们在源码中搜索这个id试试:

我们发现,该id出现了2次,定位到它们:
这个是dom节点本身:

这个是js脚本:

注意,从js脚本中,我们不仅发现了id, 还发现descUrl
这个属性,我们猜测它指向的就是详情图片。
访问试试:

可以发现,该url返回了一连窜的图片。对比可知,它们确实是商品的详情图片。
通过以上步骤,我们解决了如何查询图片来源的问题。如果我们眼瞎:),没注意到descUrl
这个属性。有其它办法定位到图片的来源吗?
..
..
..
..
我们再提供另一种方案。
首先,在浏览器控制台进行全局搜索(cmd+option+f),搜索的是之前复制的详情图片地址:

我们不仅搜到了图片,还看到了请求源: desc.alicdn... 。接着我们看看这个请求是在哪里发出的:

从item.htm中发出,即请求的信息写在item.htm源码中,所以我们只需要在源码中搜索desc.alicdn
便能找到图片在哪里了:

殊途同归,我们又定位到了descUrl
。
以上是2种定位所需要内容的方式。接下来给一个具体的代码实现。
代码实现
我们使用TypeScript来写,以增加可读性。
taobao.ts
import request from 'request';/*** 获取淘宝商品详情页面的html源码* @param {string} itemUrl 页面地址,比如 https://item.taobao.com/item.htm?id=555217237330* @return {Promise<string>} 页面html源码*/function fetchHTML(itemUrl: string): Promise<string> {return new Promise((resolve, reject) => {request({url: itemUrl}, (err, res, body) => {err ? reject(err) : resolve(body)});})}/*** 获取淘宝商品详情图片的源码* @param {string} descUrl 图片地址* 比如 desc.alicdn.com/i4/550/210/555217237330/TB1QacrQgHqK1RjSZFP8qwwapla.desc%7Cvar%5Edesc%3Bsign%5E68d509b027183b2087ae0ee50be0e288%3Blang%5Egbk%3Bt%5E1554975361* @return {Promise<string>} 图片源码*/function fetchImages(descUrl: string): Promise<string> {return new Promise((resolve, reject) => {request({url: descUrl}, (err, res, body) => {err ? reject(err) : resolve(body)});});}// 用来解析图片源码地址const desc_url_regex = /(desc.alicdn.com[^']+?)'/;// 用来解析图片const image_regex = /src="([^"]+?)"/;/*** 获取淘宝详情图片列表** 返回的是一个图片地址迭代器,方便按需解析(不是所有时候都需要所有图片)** @param {string} itemUrl 商品url* @return {AsyncIterableIterator<String>} 图片地址迭代器*/export async function* getImages(itemUrl: string): AsyncIterableIterator<String> {const html = await fetchHTML(itemUrl);const [, descUrl] = desc_url_regex.exec(html);const imageHtml = await fetchImages('http://' + descUrl);for (const matches of imageHtml.matchAll(image_regex)) {yield matches[1]}}
taobao.test.js
/*** 获取淘宝商品详情图片的源码* @param {string} descUrl 图片地址* 比如 desc.alicdn.com/i4/550/210/555217237330/TB1QacrQ...* @return {Promise<string>} 图片源码*/function fetchImages(descUrl: string): Promise<string> {return new Promise((resolve, reject) => {request({url: descUrl}, (err, res, body) => {err ? reject(err) : resolve(body)});});}
结束语
以上只是利用桌面端浏览器定位爬虫内容的方式。移动的app,因为没有html页面,则需要另一种方式,比如截取app请求并作出分析。以后有空再写。
写爬虫只是第一步,部署运行的过程中会有另外的问题。比如部分网站会做反爬处理(限制ip,限制访问次数等)。如何减少反爬带来的影响?
欢迎评论或私聊。




