最近有一个小需求,须要根据用户输入的某宝的店铺 url,检查地址是否存在,并抓取店铺名称。某宝店铺 url 的 title 一般是 xx-xx-xx 的形式,中间的 xx 就是对应的店铺名称。html
这个需求很简单,根据 url 直接发送 get 请求,利用 cheerio 解析获得的 html 文件,就能够得到 title 的内容,再切割字符串就能够得到店铺名称。git
为了验证某宝店铺页面的 title 均是 xx-xx-xx 形式,而且中间的 xx 就是店铺名称,就要搜索大量店铺页面名称。一个个查看即耗时间也不实际,因而决定利用爬虫快速获取店铺名称。其实爬虫的基本思路并不难,更重要的在于分析页面结构,以获取须要的内容。github
页面大体分为3种状况:web
① 直出页面,获取到 html 文件就能够解析须要的内容浏览器
② 动态页面,所需内容是数据经过接口得到的,直接请求接口便可并发
③ 动态页面,找不到相关数据接口,借助 PhantomJS 获取完整的页面性能
怎样能快速得到大量的店铺 url 呢?某宝的宝贝列表中,宝贝信息实际上是包含了该宝贝所在店铺首页的连接,经过宝贝列表就能够快速得到店铺 url。经过分析页面,很不幸,宝贝列表是脚本动态加载的,而且找不到相关数据的接口,惟有借助 PhantomJS 了。PhantomJS 虽然强大,但性能并非很好,不过为了知足个人好奇心,足够了。lua
PhantomJSurl
PhantomJS 是一个 webkit 的 JavaScript API,至关于一个阉割版的浏览器,详情可查看官网spa
PhantomJS 获取并解析页面的语法也很简单,完整demo
// page。open 打开并加载 url,这里的 url 为宝贝列表页面
page.open(url, function (s) { console.log('index ' + index + ' ' + s) if (s === 'success') { setTimeout(function () {
// page.evaluate 用于解析页面内容,详情请看官网 const shopUrl = page.evaluate(function () { const urls = [] const ele = document.getElementsByClassName('J_ShopInfo') for(var i = 0, len = ele.length; i < len; ++i) { const item = ele[i] urls.push(item.href) } return urls }) getTitle(shopUrl, 0, getShopsName(index + 44, max)) }, 1500) } })
getTitle 用于获取店铺首页 url 的 title
function getTitle (urls, i, cb) { if (i < urls.length) { const url = urls[i] page.open(url, function(s) { if (s === 'success') { const result = page.evaluate(function () { return document.title }) console.log(i + ' ' + result) titles.push(result) getTitle (urls, i + 1, cb) } }) } else { cb && cb() } }
在访问宝贝列表页面和店铺页面时,因为某宝的反爬虫措施,这里都用了递归搜索,确保不是并发请求页面,不然页面会获取失败。setTimeout 是为了等待页面中所需内容已加载后再解析。若是获取到页面后当即解析,只会获得一个几乎空白的页面。
因为页面都包含大量的图片信息,能够经过设置
page.settings.loadImages = false
不加载内联图片,减小 PhantomJS 的性能消耗。
让程序本身一直循环执行,就能够获取到大量的数据啦