【实验目的】
1.什么是爬虫
2.利用爬虫可以做哪些有趣的事
3.常见的爬虫框架
4.关于webmagic
5.爬虫架构
6.爬取策略
7.分析电商网站源码结构
8.分析电商评论部分字段含义
9.搭建爬虫代码框架
10.模拟爬虫为普通用户
11.处理页面内容
12.设置Scheduler
13.执行测试
【实验原理】
什么是爬虫
网络爬虫,也叫网络蜘蛛(spider),是一种用来自动浏览万维网的网络机器人。其目的一般为编纂网络索引。
网络搜索引擎等站点通过爬虫软件更新自身的网站内容或其对其他网站的索引。网络爬虫可以将自己所访问的页面保存下来,以便搜索引擎事后生成索引供用户搜索。
爬虫访问网站的过程会消耗目标系统资源。不少网络系统并不默许爬虫工作。因此在访问大量页面时,爬虫需要考虑到规划、负载,还需要讲“礼貌”。 不愿意被爬虫访问、被爬虫主人知晓的公开站点可以使用robots.txt文件之类的方法避免访问。这个文件可以要求机器人只对网站的一部分进行索引,或完全不作处理。
互联网上的页面极多,即使是最大的爬虫系统也无法做出完整的索引。因此在公元2000年之前的万维网出现初期,搜索引擎经常找不到多少相关结果。现在的搜索引擎在这方面已经进步很多,能够即刻给出高质量结果。
爬虫还可以验证超链接和HTML代码,用于网络抓取。
利用爬虫可以做哪些有趣的事
1.爬取古诗文
- 《小松》 唐代 杜荀鹤
- 自小刺头深草里,而今渐觉出蓬蒿。
- 时人不识凌云木,直待凌云始道高。
2.爬取电商数据: 如意淘、惠惠购物助手、西贴、购物党
3. 爬取社会化媒体
4.爬取金融数据,量化分析
5.爬取新闻数据,舆情、 文章聚合等
常见的爬虫框架
1.Java语言开发的分布式爬虫:Nutch
分布式爬虫,主要是解决两个方面的问题:①海量URL管理 ②网速。
Nutch一般应用于搜索引擎
Nutch依赖于Hadoop运行
2.JAVA语言开发的单机爬虫:Crawler4j、WebMagic、WebCollector
3.Python语言开发的单机爬虫:scrapy、PySpider
4.自己动手,编写爬虫
关于webmagic
WebMagic是一个简单灵活的Java爬虫框架。基于WebMagic,你可以快速开发出一个高效、易维护的爬虫。
WebMagic的设计参考了业界最优秀的爬虫Scrapy,而实现则应用了HttpClient、Jsoup等Java世界最成熟的工具,目标就是做一个Java语言Web爬虫的教科书般的实现。
网站:http://webmagic.io/
中文文档:http://webmagic.io/docs/zh/
爬虫架构
WebMagic的结构分为Downloader、PageProcessor、Scheduler、Pipeline四大组件,并由Spider将它们彼此组织起来。这四大组件对应爬虫生命周期中的下载、处理、管理和持久化等功能。WebMagic的设计参考了Scapy,但是实现方式更Java化一些。
而Spider则将这几个组件组织起来,让它们可以互相交互,流程化的执行,可以认为Spider是一个大的容器,它也是WebMagic逻辑的核心。
WebMagic总体架构图如下:
组件讲解
1.Downloader
Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了Apache HttpClient作为下载工具。
2.PageProcessor
PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。
在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。
3.Scheduler
Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。
除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。
4.Pipeline
Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。
Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。
爬取策略
1.并行策略
一个并行爬虫是并行运行多个进程的爬虫。它的目标是最大化下载的速度,同时尽量减少并行的开销和下载重复的页面。为了避免下载一个页面两次,爬虫系统需要策略来处理爬虫运行时新发现的URL,因为同一个URL地址,可能被不同的爬虫进程抓到。
2.重新访问策略
网站的属性之一就是经常动态变化,而爬取网站的一小部分往往需要花费几个星期或者几个月。等到网站爬虫完成它的爬取,很多事件也已经发生了,包括增加、更新和删除。 在搜索引擎的角度,因为没有检测这些变化,会导致存储了过期资源的代价。
3.平衡礼貌策略
爬虫相比于人,可以有更快的检索速度和更深的层次,所以,他们可能使一个站点瘫痪。不需要说一个单独的爬虫一秒钟要执行多条请求,下载大的文件。一个服务器也会很难响应多线程爬虫的请求。 就像Koster所注意的那样,爬虫的使用对很多任务作都是很有用的,但是对一般的社区,也需要付出代价。使用爬虫的代价包括:
网络资源:在很长一段时间,爬虫使用相当的带宽高度并行地工作。
服务器超载:尤其是对给定服务器的访问过高时。
质量糟糕的爬虫,可能导致服务器或者路由器瘫痪,或者会尝试下载自己无法处理的页面。
个人爬虫,如果过多的人使用,可能导致网络或者服务器阻塞。
对这些问题的局部解决方法是漫游器排除协议(Robots exclusion protocol),也被称为robots.txt议定书
4.选择策略
链接跟随限制
URL规范化
路径上移爬取
主题爬取
【实验环境】
Linux Ubuntu 16.04
jdk-7u75-linux-x64
eclipse-java-juno-SR2-linux-gtk-x86_64
【实验内容】
实验需求:本实验通过在eclipse创建项目,采集 http://59.64.78.41:40000/jd
页面评论商品的信息
【实验步骤】
一、分析电商网站源码结构
1.使用Chrome浏览器,打开京东锤子手机页面,网址为: http://59.64.78.41:40000/jd
按键盘上的F12键,进入开发者工具页面。点击开发者工具里的“NetWork”,再点击商品详情页里的“商品评论”,就可以看到浏览器请求的数据文件。
利用Filter过滤网址,输入comment,查找相关的网址请求url,此请求就是获取商品评论内容。
我们可以看到右侧,Request URL为:http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=1"
相应地切换到【Preview】,可以看到这是一个json串,包含很多信息,包括10条评论。
2.根据上述分析,我们发现获得评论数据的请求url为:
第一页:http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=1
第二页:http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=2
第三页:http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=3
二、分析电商评论部分字段含义
首先看下返回的Json形式的评论,可以看到格式比较混乱,可读性较差
想办法格式化一下,访问代码格式化工具https://www.json.cn/,使用此工具,对Json评论进行格式化。可以看到如下格式比较清晰的效果:
在结构化的Json中,查找有用的信息。
- productCommentSummary 存储了对该商品全部评论的汇总信息;
- comments 存储了当前页面的10条评论数据
productCommentSummary中详细内容:
- "productCommentSummary": {
- "goodRateShow": 95, //好评率
- "poorRateShow": 3, //差评率
- "poorCountStr": "1900+",
- "averageScore": 5, //平均分
- "generalCountStr": "1600+",
- "oneYear": 0,
- "showCount": 21000,
- "showCountStr": "2.1万+",
- "goodCount": 64000, //好评数
- "generalRate": 0.024,
- "generalCount": 1600, //中评数
- "skuId": 4432058,
- "goodCountStr": "6.4万+",
- "poorRate": 0.028,
- "afterCount": 2400,
- "goodRateStyle": 142,
- "poorCount": 1900, //差评数
- "skuIds": null,
- "poorRateStyle": 4,
- "generalRateStyle": 4,
- "commentCountStr": "6.8万+",
- "commentCount": 68000,
- "productId": 4432058, //商品id
- "afterCountStr": "2400+",
- "goodRate": 0.948,
- "generalRateShow": 2 //中评率
- },
comments中一条评论的结构:
- “id": 10432588299,
- “guid": "6c1d83b1-ac45-4189-a041-774eaff87df9",
- “content": "割手,相当的割手,无语了", //评论内容 √
- “creationTime": "2017-05-22 23:37:24", //写评论的时间 √
- “isTop": false, //是否置顶
- “referenceTime": "2017-05-20 18:35:11", //收货时间 √
- “firstCategory": 9987, //第一分类 √
- “secondCategory": 653, //第二分类 √
- “thirdCategory": 655, //第三分类 √
- “replyCount": 0,
- “score": 3, //打分 √
- “nickname": "j***柜", //昵称 √
- “userClient": 2,
- “productColor": "碳黑色",
- “productSize": "32GB",
- “userLevelName": "金牌会员", //会员级别 √
- “plusAvailable": 0,
- “productSales": [
- {
- "dim": 3,
- "saleName": "选择套装",
- "saleValue": "官方标配"
- }
- ,
- “userClientShow": "来自京东iPhone客户端", //评论设备
- “isMobile": true, //是否移动端
- “days": 2, //评论时间距【收货/下单】时间多长时间
- “afterDays": 0
了解了相关字段含义,下面开始使用webmagic,编写爬虫,爬取商品评论。
三、搭建爬虫代码框架
1.切换目录到/data/目录下,创建名为edu1的目录
- cd /data/
- mkdir /data/edu1
2.切换目录到/data/edu1目录下,使用wget命令,下载webmagic爬虫项目所依赖的lib包
- cd /data/edu1
- wget http://59.64.78.41:60000/allfiles/edu1/webmagic-0.7-libs.tar.gz
将webmagic-0.7-libs.tar.gz压缩包,解压缩。
- tar -xzvf webmagic-0.7-libs.tar.gz
3.打开eclipse开发工具
新建Java Project,命名为pachong1
点击项目名pachong1,新建一个目录,命名为libs,并将/data/edu1/webmagic-0.7-libs下的所有的jar包,拷贝到libs目录下。并选中所有jar包,右键点击“Build Path” => “Add to Build Path”
4.在pachong1项目下,点击src => New => Package新建一个包
在弹出窗口中,输入包名my.webmagic
在my.webmagic包下,新建class类
将新建的类,命名为GetComments。搭建完的代码框架如下:
5.代码编写
在WebMagic里,实现一个基本的爬虫只需要编写一个类,实现 us.codecraft.webmagic.processor.PageProcessor接口即可。这个类基本上包含了抓取一个网站,需要写的所有代码。实现接口后,重写里面的getSite和process方法
- import us.codecraft.webmagic.Page;
- import us.codecraft.webmagic.Site;
- import us.codecraft.webmagic.processor.PageProcessor;
- public class GetComments implements PageProcessor {
- @Override
- public Site getSite() {
- return null;
- }
- @Override
- public void process(Page arg0) {
- }
- }
四、模拟爬虫为普通用户
getSite()方法,返回的数据类型为us.codecraft.webmagic.Site类型。也就是对当前爬虫,进行设置,包括编码、抓取间隔、超时时间、重试次数等,也包括一些模拟的参数,例如User Agent、cookie,以及代理的设置。
- private Site site = Site.me().setDomain("59.64.78.41:40000").setSleepTime(2000);
如果想设置更详细内容,可以这样做:
- private Site site = Site.me()
- .setDomain("59.64.78.41:40000")
- .setSleepTime(2000)
- .addCookie("TrackID", "1_VWwvLYiy1FUr7wSr6HHmHhadG8d1-Qv-TVaw8JwcFG4EksqyLyx1SO7O06_Y_XUCyQMksp3RVb2ezA")
- .addCookie("__jda", "122270672.1507607632.1423495705.1479785414.1479794553.92")
- .addCookie("__jdb", "122270672.1.1507607632|92.1479794553")
- .addCookie("__jdc", "122270672")
- .addCookie("__jdu", "1507607632")
- .addCookie("__jdv", "122270672|direct|-|none|-|1478747025001")
- .addCookie("areaId", "1")
- .addCookie("cn", "0")
- .addCookie("ipLoc-djd", "1-72-2799-0")
- .addCookie("ipLocation", "%u5317%u4EAC")
- .addCookie("mx", "0_X")
- .addCookie("rkv", "V0800")
- .addCookie("user-key", "216123d5-4ed3-47b0-9289-12345")
- .addCookie("xtest", "4657.553.d9798cdf31c02d86b8b81cc119d94836.b7a782741f667201b54880c925faec4b")
- .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11")
- .addHeader("Accept", "text/html;q=0.9,*/*;q=0.8")
- .addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3")
- .addHeader("Connection", "close")
- .addHeader("Referer", "http://59.64.78.41:40000/jd")
- .setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31");
这里一些项目内容,例如setDomain的值、setUserAgent的值,可以从这里获取
这里的setDomain是请求的Host地址
最终,将site对象,在getSite方法作为结果返回。
- @Override
- public Site getSite() {
- return site;
- }
五、处理页面内容
process方法,是webmagic爬虫的核心部分,可以从下载到的Html页面,抽取到想要的信息。WebMagic里主要使用了三种抽取技术:XPath、正则表达式和CSS选择器。此处使用page.getJson(),得到当前页码Json形式的全部评论,并且存储到ten这个变量中。
- public void process(Page page) {
- page.putField("ten", page.getJson().toString());
- }
Scheduler是WebMagic中进行URL管理的组件。一般来说,Scheduler包括两个作用:①对待抓取的URL队列进行管理; ②对已抓取的URL进行去重。
WebMagic内置了几个常用的Scheduler:
通过观察url可以发现规律,页码从1开始依次增加,可以抓取到每个页面的10条评论。
此处我们使用QueueScheduler,使用for循环,得到100个url,并将待抓取的url放到内存队列中存储。
创建main函数,并在main函数中编写代码:
- String url_init = "http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=1";
- String url_pattern = "http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=";
- String output = "/data/edu1/tmp/";
- QueueScheduler scheduler = new QueueScheduler();
- Spider spider = Spider.create(new GetComments())
- .addUrl(url_init)
- .setScheduler(scheduler)
- .addPipeline(new JsonFilePipeline(output))
- .addPipeline(new ConsolePipeline());
- for (int i = 0; i < 100; i++) {
- Request request = new Request();
- request.setUrl(url_pattern + i);
- scheduler.push(request, spider);
- }
- spider.thread(5).run();
在main函数中,Spider是爬虫启动的入口。在启动爬虫之前,我们需要使用一个PageProcessor创建一个Spider对象,然后使用run()进行启动。同时Spider的其他组件(Downloader、Scheduler、Pipeline)都可以通过set方法来进行设置。
- .addUrl(url_init)
- .setScheduler(scheduler)
- .addPipeline(new JsonFilePipeline(output))
- .addPipeline(new ConsolePipeline());
在此段代码中
.addUrl 爬虫初始化时,需要爬取的页面
.setScheduler 设置爬虫计划,将待爬取的url告诉爬虫
.addPipeline(new JsonFilePipeline(output)) 设置爬取结果存储形式和位置,这里以Json形式存储
.addPipeline(new ConsolePipeline()) 设置爬取结果存储形式和位置,这里将结果同时输出到console页面。
六、执行测试
完整代码
- package my.webmagic;
- import us.codecraft.webmagic.Page;
- import us.codecraft.webmagic.Request;
- import us.codecraft.webmagic.Site;
- import us.codecraft.webmagic.Spider;
- import us.codecraft.webmagic.pipeline.ConsolePipeline;
- import us.codecraft.webmagic.pipeline.JsonFilePipeline;
- import us.codecraft.webmagic.processor.PageProcessor;
- import us.codecraft.webmagic.scheduler.QueueScheduler;
- public class GetComments implements PageProcessor {
- // 对爬取站点的一些属性进行设置,例如:设置域名,设置代理等;
- private Site site = Site.me().setDomain("59.64.78.41:40000").setSleepTime(2000);
- public Site getSite() {
- return site;
- }
- public void process(Page page) {
- page.putField("ten", page.getJson().toString());
- }
- public static void main(String[] args) {
- String url_init = "http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=1";
- String url_pattern = "http://59.64.78.41:40000/jdjson?callback=fetchJSON_comment98vv111&productId=39215375204&score=0&sortType=5&pageSize=10&isShadowSku=0&fold=1&page=";
- String output = "/data/edu1/tmp/";
- QueueScheduler scheduler = new QueueScheduler();
- Spider spider = Spider.create(new GetComments()).addUrl(url_init)
- .setScheduler(scheduler)
- .addPipeline(new JsonFilePipeline(output))
- .addPipeline(new ConsolePipeline());
- for (int i = 0; i < 100; i++) {
- Request request = new Request();
- request.setUrl(url_pattern + i);
- scheduler.push(request, spider);
- }
- spider.thread(5).run();
- }
- }
在项目上,右键,点击Run As => Java Application
打开桌面“终端模拟器”,进入命令行模式
切换目录到/data/edu1/tmp/59.64.78.41:40000下,查看数据情况
- cd /data/edu1/tmp/59.64.78.41:40000
- ls
至此,实验结束!