HtmlUnit 网络爬虫 菜鸟的学习笔记(二)

此次我以爬新浪微博为例,这个过程太纠结了,参考了好多大神的帖子,不过仍是遗留了不少问题,咱们慢慢来看,但愿大神帮于指正,个人方法暂时来讲仍是比较挫的php

        登录问题html

        爬新浪微博首先要登录,以前爬的妹纸网站,因为不用登录,因此没这一步,可是爬新浪微博咱们必需要先登陆,可是要涉及到一个问题,那就是验证码,验证码从我如今百度到的,和本身的理解,感受暂时仍是不能解决的,除非手工输入,由于自己验证码就是防止恶意登录,防爬虫的,因此建议想试试的朋友用暂时用不输入验证码的帐号试试(关于验证码,期盼大神能够给些提示web

        下面是demo代码json

WebClient webClient = new WebClient();
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setCssEnabled(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.getOptions().setThrowExceptionOnScriptError(false);

HtmlPage htmlPage = null;

try {
    htmlPage = webClient.getPage("http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)");
    HtmlInput username = (HtmlInput) htmlPage.getElementsByName("username").get(0);
    HtmlInput password = (HtmlInput) htmlPage.getElementsByName("password").get(0);

    HtmlInput btn = htmlPage.getFirstByXPath(".//*[@id='vForm']/div[3]/ul/li[6]/div[2]/input");

    username.setValueAttribute("****");
    password.setValueAttribute("****");
    btn.click();
} catch (IOException e) {
    e.printStackTrace();
}

            代码和以前的差很少太多,多了一些参数设置,经过方法命名就应该能够大致知道啥含义了,我就不过多解释了,可是可能有人会问为何webClient.getPage的url不是www.weibo.com 呢?由于若直接get那个www.weibo.com,获得的html,debug看,全是一些js代码,没有任何登录模块而言,可见新浪的登录模块多半是脚本画出来的,因此很差,而这个网站,我开始是参考之前一个大神写的  http://blog.csdn.net/bob007/article/details/29589059 api

            这个网站打开实际上是新浪通行证的登录页面
浏览器

           

            开始我想为啥是这个界面,因此后面用httpwatch看了一下经过www.weibo.com登录的时候整个请求过程dom

             能够看到,在输入完密码和帐号以后,咱们post的地址正是这个地址,也就是说,新浪微博的登录内部应该是这样的            工具

             1. 请求www.weibo.com 获得登录页面,输入完用户密码post

              2. 提交请求到新浪通行证,而后点击登录,完成登录操做
学习

            咱们日常用的微博帐号,对于新浪而言,实际上是新浪通行证的一种,这样也就好理解了

           

            咱们再回到htmlunit上,咱们获取了新浪通行证的登录页面后(htmlpage对象),如何获取到具体的用户名和密码的控件呢,这个你们能够本身debug一下就很清楚了,而后用htmlpage.asXml()这个方法解读一下这个页面的各个元素,看一下就知道了

            而获取登录按钮的方式也是直接参考以前那个大神里的作法,用到了api是getFirstByXPath这个方法,这个里的XPath语法就是w3c标准语法,能够参考http://www.w3school.com.cn/xpath/学习一下,有了这个语法对于页面的任何节点,只要稍加分析,基本均可以拿到的

            以后就简单啦,获取到了用户名,密码输入框,还有提交按钮,咱们最后三行代码就是把用户名和密码set进去,而后点击提交按钮,这就完成了登录操做,是否是感受到这个代码逻辑就是和页面操做同样嘛,这也体现了模拟浏览器的描述了

            由于你如今已经登录了,因此如今你就能够浏览你的主页和看你关注的人的微博啦

            可是你们这里要注意一个很重要的问题,就是微博的展现方式,你们实际操做也能够感受的到,展现微博时是这么一个过程

            1. 展现一部分微博

            2. 滚动条向下滚动,刷出一部分新的微博

            3. 滚动几回后,最后页面底部出现分页控件

            4. 点击下一页,又展现一部分微博,重复2-4的过程了

            因此我开始就遇到这样的问题,我开始用下面的代码请求个人主页,而且打印出了个人微博,惋惜只有15条,由于个人滚动条没有下拉,因此没有请求到更多的微博

page3 = webClient.getPage("http://weibo.com/5622296819/profile?topnav=1&wvr=6");
List<HtmlDivision> htmlDivisions = (List<HtmlDivision>) page4.getByXPath("//div[@class='WB_text W_f14']");

for(i = 0; i < htmlDivisions.size(); i++) {
    System.out.println("第" + (counter++) + "条微博: "
                    + htmlDivisions.get(i).getTextContent().trim());
}

            因此我就开始了处处百度如何用htmlunit模拟滚动条滚动,找了好多,模拟这个下拉这个动做基本看无法搞(你们可能够看看这个可怜的兄弟,14年就遇到这个问题了,他最后两段说出了个人心声 http://stackoverflow.com/questions/23491638/is-there-a-way-to-trigger-scroll-event-with-htmlunit-or-is-it-not-possible-at-al  )

            不过有人提出能够模拟滚动条下拉这个请求,而不是模拟这个动做,好比这个大神http://blog.csdn.net/zhoujianfeng3/article/details/21395223 可是代码仍是不全,我试着尝试,并且他模拟的url是14年的,不报但愿的试了一下,果真是不行的,可是他的想法仍是给我很大的启发,我参照他的方式,经过httpwatch看了一下,如今的滚动下拉请求基本是这个样子(这是我关注的一个帐号的微博,由于微博比较多,能够用来练习抓)

            http://weibo.com/p/aj/v6/mblog/mbloglist?ajwvr=6&domain=100505&from=myfollow_all&pre_page=1&page=1&max_id=&end_id=3882220290581087&pagebar=0&filtered_min_id=&pl_name=Pl_Official_MyProfileFeed__22&id=1005051645851277&script_uri=/u/1645851277&feed_type=0&domain_op=100505&__rnd=1441077128511 

            通过几回分析,注意其中的这两个参数,page=1和pagebar=0,这个page就是当前这个分页,而这个pagebar是滚动的那个序列,也就是继续滚下去的话,page=1不变,pagebar要变为1,若分页的时候,page要变为2(变为相应页数),而pagebar又要从0开始,按照以前说的那个微博展现的过程理解一下就不难了

            可是注意上面这个url是滚动的url,而点击分页又是另外一个,你们能够本身用httpwatch看一下就知道了,这里就不赘述

            说完分析思路,再说说作法

            这里滚动下拉的请求,返回的是json数据,不是一个html页面,因此就不能再用webClient.getPage了,你们要注意一下,而当前从我百度的来看,htmlunit还不能很好的解析json,因此这里参考我以前说的大神的思路,用到了另外一个爬虫工具JSoup,来解析,demo代码以下

WebRequest requestOne = new WebRequest(new URL(url), HttpMethod.GET);
WebResponse jsonOne = webClient.loadWebResponse(requestOne);
JSONObject jsonObj = JSONObject.fromObject(jsonOne.getContentAsString());

String data = (String) jsonObj.get("data");

Document doc = Jsoup.parse(data);
Elements elementsTwo = doc.select("div[class=WB_text W_f14]");

for (int i = 0; i < elementsTwo.size(); i++) {
     Element element = elementsTwo.get(i);
     System.out.println("第" + (counter++) + "条微博: "
                    + elementsTwo.get(i).text());
}

            url就是分页的url,这样用HtmlUnit来构建一个Web的请求,而后获取到json返回的结果,转换为JSONObject对象,再用JSoup来解析json的字符转,这里的doc.select后面参数的语法是CSSQuery语法,和Xpath差不太多,你们随即可以百度一下,也是比较好理解的,最后打印一下全部的微博就能够了

            差点忘了,这里还须要增长新的依赖   

<!-- json begin -->
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <classifier>jdk15</classifier>
    <version>2.2</version>
</dependency>
<!-- json end -->

<!-- jsoup begin -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.6.3</version>
</dependency>
<!-- jsoup end -->

            最后我是把这个微博帐号里的微博5000多条微博,直接写到一个文件里了,算是完成了最基本的了,固然我知道这也只是爬虫最基本的小demo,后面老大没有给我分配其余任务的时候,我会再继续专研哈,但愿大神们多指正

            

            其实这里也只是给你们提供思路了,多多debug分析一下就行了,固然我这个办法仍是属于比较笨的,如有大神有更吊的方法,欢迎告诉我o(^▽^)o

相关文章
相关标签/搜索