继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

爬虫的思考

xpbob
关注TA
已关注
手记 152
粉丝 1.6万
获赞 380

爬虫不算特别陌生了,尤其是python崛起后,很多推广python的方式就是做爬虫的案例,例如可以爬取新闻网站等等,代码量不多,而且开发还有成就感。下面就说说对爬虫的一些思考。

网站的分类

网站我分为了两类

  • 一种是表现结果是静态的,例如新闻网站,一个新闻一旦发布出来,url内容就不会改变了。并不会因为时间的变化,新闻内容而改变。还有公告网站,公告都贴出来了,如果更新也是弄一页新的,或者是更新内容,并不会有更多的交互部分。
  • 一种是前后台分离的动态网站,例如获取新的数据来展示table,进行分页查询,还有例如erp系统,动态的增加数据,刷新数据,页面的东西可以说是时时刻刻在变动,格式都是固定的,只是数据每次都把新的填充进来。

很多教程都是第一种网站,爬取基本不动的内容。里面的数据,格式都是固定的,我们爬取获取到html。把前端的数据根据一定的规则获取出来。

第二种一般不会拿来做为入门手段。因为这种系统一般都包含校验,权限控制,例如我们可能必须登录才能做后面的操作,并不能直接那个url就是html。

浏览器

对于第二种情况,我们不妨思考一下,浏览器是什么。
浏览器是一个程序,帮助我们进行http请求,并且可以获取到返回的数据,而且本地可以存cookie,下次请求可以携带这些数据。
我们最开始做的登录系统,就是把用户的登录信息存到session里。由于session成功创建,请求返回时,头里带了jsessionid的信息,下次如果再次请求,都会携带这些信息。后台程序可以根据这个数据来进行校验,判断这个url是否能正常进行访问。

模拟浏览器

上面的例子大概说了我们编程的方式,还有浏览器的功能,是不是说我们可以通过模拟浏览器来达到这个效果呢。
如果是java的代码,我们去搜索,很大程度,搜到的结果就是以下两个关键字,webmagic,selenium。webmagic是爬虫框架。selenium是浏览器驱动,可以模拟浏览器获取到本地的cookies。然后用webmagic进行访问的时候可以增加对应的cookies。
但是我的思路不是这样的,因为前后台分离的情况下,后台返回的数据才是我们要获取的,我们爬取的不应该是页面了,而是通过模拟浏览器的功能直接获取到返回的数据。
我们都知道http协议是明文的。我们可以通过浏览器开启watch功能,看到请求发起以后传递的数据,请求头,请求体;以及请求返回后获取的响应头和响应体。
那我们自己就可以保存这些数据了,自己把cookies获取到,下次发起请求的时候就可以加入了。

httpclient

经过上面的分析,貌似情况简单了,我们只用httpclient就可以做到了。首先第一步是获取请求,这里我们推荐使用抓包工具,而不是浏览器自带的。在一些重定向的操作中,自带的工具很可能抓不到。
下面是模拟浏览器的代码,就是在协议里告诉后台程序,我们是什么

    private static void setPostHeader(HttpPost httpPost) {
        httpPost.setHeader("X-Requested-With", "XMLHttpRequest");
        httpPost.setHeader("Accept", "application/json, text/javascript, */*; q=0.01");
        httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36");
    }

请求的代码直接发出来

        //创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();
        //创建post方式请求对象
        HttpPost httpPost = new HttpPost(URL);

        //装填参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();

       nvps.add(new BasicNameValuePair("password", "xxxxx"));
        //设置参数到请求对象中
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));

        setPostHeader(httpPost);

        //执行请求操作,并拿到结果(同步阻塞)
        CloseableHttpResponse response = client.execute(httpPost);
        //获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            //按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, "UTF-8");
        }
        Header[] allHeaders = response.getAllHeaders();
        if (body.contains("success")) {
            List<String> cookiesTmp = new ArrayList<>();
            for (Header allHeader : allHeaders) {
                if ("Set-Cookie".equals(allHeader.getName())) {
                    String[] split = allHeader.getValue().split(";");

                    if (split.length > 0) {
                        cookiesTmp.add(split[0] + ";");
                    }

                }


            }
            cookies = cookiesTmp;
        }
        EntityUtils.consume(entity);
        //释放链接
        response.close();

代码逻辑很简单,创建连接,设置头,和参数。在成功后把cookies 获取出来,再下次请求的时候再带上。

    private String setCookies() {
        StringBuilder sb = new StringBuilder();
        final List<String> cookiesTmp = cookies;
        for (String cookie : cookiesTmp) {
            sb.append(cookie);
        }
        return sb.toString();
    }

设置的方式就是明文,这里需要参考具体的http请求来做。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP