这套系统能做什么:
1:可支持自动化测试,简单的黑盒测试和功能测试,简单实现模拟真人注册,登陆,点击按钮,拖拽页面,滚动下滑和获取返回值比较,模拟真人操作流程,大大简化了人工QA成本。
2:跟以往静态爬虫不同,以往的curl获取资源再解析和Xsoup/Jsoup等爬虫都只能够爬取网页上已展示出来的静态页面,动态加载的数据都无法获取。这套系统能爬取任意一种触发条件后出现的动态数据(包括滚动,懒加载,点击,自动输入设置好的参数,鼠标悬浮)。
如果当爬虫用,什么网站可以爬取?被抓取的网站有什么防范措施?
目前测试成功的有各种新闻页面(某浪新闻,搜某新闻),各种论坛和小说贴吧漫画之家,各种小说网站(红某某香,天某涯)等等,在测试时候多次爬取某宝商品二三级详情页的时候会被检测出机器人操作,随即要求你登陆某宝账号,后来用一个小号账号密码作为输入参数给机器人拿去输入登陆,但是有图片拼图识别认证,要拖动拼图准确拼入不同的位置,这一部分要破解要下成本做图片识别,所以没有继续下去,只草率抓取了一些一级页面图片和产品信息。
经过多次测试由此可见,要防范爬虫其实还是比较好入手的,加一些检测,对异常用户添加设备号和IP的灰名单,放拦截器去拦截那一部分用户强制登陆或者强制验证(拖拽拼图,点点乐,计算题等等,这些前端都已经很多了),验证成功后再放开拦截。
说完了它能干什么,那么下面开始介绍下使用到的技术
selenium:
它是用JavaScript写出来的一套自动化测试工具,因为是用JavaScript,所以它能支持大部分浏览器(IE6以上,Firefox火狐,Google Chrome谷歌,Safari等等),装了相对应版本的浏览器驱动后,它能自动调起浏览器自己进行操作,爬虫中它就是冲锋士兵去触发全部的JavaScript页面渲染,数据都出来后,爬虫再进场收割数据返回。因为浏览器各个版本都有对应各个版本驱动,所以一定要准确安装,不然启动不了。
IE的驱动下载地址:http://selenium-release.storage.googleapis.com/index.html
Firefox火狐驱动下载地址:https://github.com/mozilla/geckodriver/releases/
Google Chrome谷歌驱动下载地址: http://chromedriver.storage.googleapis.com/index.html
下载后记得要把driver驱动的下载好的路径配置到环境变量里面去,不然会报错找不到对应的驱动,下载错了版本也会报错找不到对应驱动哦。
web Magic:
web magic就是一个爬虫框架,不需要配置什么(Java 项目中只需要加入它的maven以来),便于使用和二次开发,很多方法其实跟你获取前端元素一样,可以通过dom对象操作获取(根据ID,name,tag标签名,正则表达式都可以),支持开多线程抓取,自动定时重试功能,分布式抓取等等都可以随心所欲。
web Magic最重要的有四个模块:
看图看英文很难理解,这里粗暴简单翻译一下:
Downloader:这个我们基本不用管,它是从网上下载页面的其实就是一个curl的作用。拿到Page资源后下一步就交给PageProcessor。
PageProcessor:很重要的一个模块!!解析页面并且根据规则抽取数据,在这里可以定义重试次数,重试时间和重试超时,还可以定义selenium调用浏览器驱动无页面启动等等(后面会有详细的代码解析)。
Scheduler:抓取的二三级URL管理,把重复URL去掉,然后根据业务需求可以再到二三级甚至更深一级的子页面去抓取,这个步骤又回到Downloader,再到PageProcessor解析,再拿到深一级的URL,所以前三个是一个闭环,可以根据业务需求不断拿到新URL去重后一层层探索下去,不断重试,设置超时等处理,直到拿到你自己想要的数据直接返回。
Pipeline:对抓取到的数据进行处理,可以直接保存到数据库或者拟定一些POJO装着直接返回,或者可以再对抓取数据进行一些处理后保存到redis,mysql,oracle持久化处理都可以,这里就像是厨师,让你对拿到的食材(数据)任意加工处理。
maven依赖:
好了,下面开始爬取某里巴巴的批发网站1688网商品数据实战演示(代码已经放上github可直接下载启动学习,代码GitHub地址:https://github.com/jojo-AI/spiders)
先看看项目工程结构
再来看下写在Controller里面的代码(解释都写得很详细了,有疑问的地方可以留言,留言必回!)
然后是PageProcessor块的源码加解释!
@Override
public void process(Page page) {
// 拿到URL并且解码,做一些域名的判断处理(因为只做了单独几个界面的抓取,1688太多界面了)
String url =page.getRequest().getUrl();
String site_url = URLDecoder.decode(url);
String[] arr = site_url.split("/");
String url_label = arr[2].trim();
//调取Firefox浏览器后台打开
FirefoxBinary firefoxBinary = new FirefoxBinary();
// 后台打开不需要开启界面版
firefoxBinary.addCommandLineOptions("--headless");
// 这里是自己安装的对应版本的火狐浏览器驱动
System.setProperty("webdriver.gecko.driver", "C:\\Program Files\\Mozilla Firefox\\geckodriver.exe");
// 这是Linux 版本安装谷歌浏览器的配置: System.setProperty("webdriver.gecko.driver", "//home//admin//geckodriver");
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.setBinary(firefoxBinary);
FirefoxDriver driver = new FirefoxDriver(firefoxOptions);
driver.get(site_url);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
WebElement elements;
// 判断是这个域名网站才采用这套爬取规则,是的,页面很多的话一个页面都是对应一套爬取规则去抓标签
if(url_label.equals("p4psearch.1688.com")){
elements = driver.findElement(By.className("offer_list"));
String htmlStr = elements.getAttribute("innerHTML");
Html html1 = new Html(htmlStr);
page.putField("ProductTitleName",html1.xpath("//div/a/div[@class='title']").all());
page.putField("ProductImage",html1.xpath("//div/a/div[@class='img']/img").css("img","src").all());
page.putField("ProductDetail",html1.xpath("//div/a/div[@class='tag_warp']").all());
page.putField("ProductPrice",html1.css("div.price_warp").css("span.price").all());
//去重
page.putField("ProductLinkHref",html1.xpath("//div[@class='offer_item']/a").css("a","href").all());
}
这里有几个坑:
1:假如class name有很长一串并且空格区分的时候,你可以只填一个,但是必须是唯一的一个,不然找到的数据会不准确。
2:注意‘-’这种特殊字符,还有一些数据是被拆分成多个内外联标签包着的,可能出现抓取不完全的情况。(例如某宝的价格信息)
3:进入详情页或者更深层级的页面抓取,有些大网站大公司会有监控和拦截,当你操作太过频繁,它就会为难你,就是让你滑拼图,做数学题,点点乐,这个虽然通过机器人操作能破解但是成本很高(做图像识别和机器学习),一般没人会这样弄,有人说哎呀那我把拼图返回到操作者前端人工破解,不可能的,你调起的浏览器是服务器上面的无界面般,你是可以把整张图发到你客户端划,但是你客户端滑动怎么同步到你服务器无界面版的抓取界面呢?所以最好就是别让它发现你,多换几个IP,多几台机器,最好有个爬虫服务集群,轮流去跑。
4:没有一套规则完美适用于各个网页,我做实验的网站中最简单的是那些小说网站和漫画网站和贴吧(标签少,规则简单,数据成片拿),最复杂的就是电商网站(拆分得很细),因此对前端的内外联标签基本常识,dom操作基本常识要有所了解。
5:有的数据是懒加载,你要让selenium模拟一下滚动再放爬虫进去收割数据,不然抓不回来。
这里是一些其他的抓取规则
好了,千幸万苦拿到数据,最后一步就是那幅图上面的Pipeline
我这里直接把resultItems赋值给我定义的resultContent后就直接返回了,选定了合适的产品再点击加入数据到数据库Mysql,当然这里可以自己DIY一下直接放入redis啊,直接持久化什么都可以。
谢谢大家,如果有写错的地方欢迎指出来,如果说的不够清楚的地方可以留言给我,留意必答。项目源码GitHub地址:https://github.com/jojo-AI/spiders