文档章节

Java使用HttpClient抓取新浪邮箱

hibegin
 hibegin
发布于 2015/11/22 12:18
字数 1242
阅读 140
收藏 0

前一段时间的无聊就简单实现了一个新浪邮箱的邮件爬取功能,主要是处理一些无法通过邮件协议读取邮件的问题,

本文以新浪邮件为例,其他邮箱实现思路大致相同

应用场景

当你有一堆通过某些途径得到了一些邮件的用户名和密码,而这个查看邮件又不需要人工去操作,那么第一想到的程序实现了,当然这就不排除有些情况没有办法通过邮件协议 POP3 读取邮件的。于是就想到了通过爬虫来完成这样的事情

思路

  • 通过使用HttpClient发送Http请求来完成对浏览器请求的模拟
  • 使用Jsoup的来完成网页的解析功能

想到这里于是就开干起来了。这里就完整的呈现当时处理的思路

对请求的分析

这里使用了firefox比较牛B的一个插件firebug

打开新浪邮箱的首页

其他的请求这里被清除了, 我们需要关心的是,当点击登陆按钮的时候浏览器都做了什么, 还是简单的输入用户名和密码就开始登陆了。

呵呵呵,第一眼一看我擦则个没有撒输入的用户和密码呢,这也藏的太深了把。一大堆奇奇乖乖的参数,难道这就行行不通了。

不过再认真一看,也就spsu,nonce,rsakv 这几个参数有一些怪怪的。 似乎使用 HttpClient + Jsoup 这条路就走不通了。

不过想了一下,这些事情都是浏览器完成的,那么按道理是可能通过程序的方式来完成的(无非也就是使用 javascritp 做一些对密码进行加密撒的吧)

  • 如果 JavaScript 的代码不是那么复杂就自己改写为Java代码
  • 过于复杂,就是 Java8 的 nashorn(JavaScript的一个运行环境) 来做吧
  • 查看手机端的请求方式是否会简单一些(实际是一样的登陆流程)

那么就需要早是那段 JavaScript 代码在做这些事情,那么就需要看都发了那些 Js 到浏览器了

看名字就可以知道了 ssilogin.js 和 login.js 嫌疑比较的大,后面通过 javascript 断点调试的方式发现是使用了 ssilogin.js 由于这个文件的内容比较的多于是选择上面的后者(Java8 解释 JavaScript的方式来完成)

中途有想过使用第三方的库 selenium 来做,不过考虑到依赖浏览器(对于运行环境都有一些要求,于是就这样被 Pass掉了)


整理完当时的思路,就来看看代码使怎样实现这个看似有些复杂的事情把。

package com.fzb.fetch.mail;

import com.fzb.common.IOUtil;
import flexjson.JSONDeserializer;
import org.apache.log4j.Logger;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.net.URLEncoder;
import java.util.*;

public class SinaEmail {

    private static Logger LOGGER = Logger.getLogger(SinaEmail.class);
    private static ScriptEngine engine;

    static {
        ScriptEngineManager engineManager = new ScriptEngineManager();
        engine = engineManager.getEngineByName("nashorn");
        try {
            engine.eval(IOUtil.getStringInputStream(HttpUtil.class.getResourceAsStream("/osslogin.js")));
        } catch (ScriptException e) {
            LOGGER.error("load sina login.js error", e);
        }
    }

    public static void fetch(String userName, String pwd) throws Exception {

        long serverTime = System.currentTimeMillis() / 1000L;
        int nonce = new Random(100000L).nextInt() + 100000;

        String password = engine.eval("password('" + serverTime + "','" + nonce + "','" + pwd + "')").toString();
        String su = URLEncoder.encode(new String(Base64.getEncoder().encode(URLEncoder.encode(userName, "UTF-8").getBytes())), "UTF-8");
        String url = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)&_=" + serverTime;
        String str = "entry=cnmail&gateway=1&savestate=30&useticket=0&su=" + su + "&service=sso&servertime=" + serverTime + "&nonce=" + nonce + "&pwencode=rsa2&rsakv=1330428213&sp=" + password + "&encoding=UTF-8&cdult=3&domain=sina.com.cn&prelt=562&returntype=TEXT";
        ResponseData<String> t = new ResponseData<String>() {
        };
        HttpUtil.postContentType(url, str.getBytes(), t, null);
        Map json = (Map) new JSONDeserializer().deserialize(t.getT());
        List<String> urls = (List) json.get("crossDomainUrlList");
        urls.add("http://mail.sina.com.cn/cgi-bin/sla.php?vt=0");
        for (String accessUrl : urls) {
            accessUrl = accessUrl + "&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript2&client=ssologin.js(v1.4.18)&_=1444529802162";
            if (!accessUrl.contains("passport.weibo.cn")) {
                HttpUtil.getContentType(accessUrl, t, null);
            }
        }
        HttpUtil.postContentType("http://m1.mail.sina.com.cn/wa.php?a=list_mail", "fid=new&order=htime&sorttype=desc&type=0&pageno=1&tag=-1&webmail=1".getBytes(), t, null);
        Map ssJson = (Map) new JSONDeserializer().deserialize(t.getT());
        Long count = (Long) ((HashMap) ((Map) ssJson.get("data")).get("total")).get("count");
        LOGGER.info(ssJson);
        LOGGER.info("email count " + count);
    }

    public static void main(String[] args)
            throws Exception {
        fetch("wozcc94@sina.cn", "hhhhhhhhh");
    }
}

nashorn 对 javascript的支持是有限的,比如document,windows.location,判断浏览器timeout 这些都是无法完成,如果出现类似的请求,先的删掉对应的 js 代码

看上去也还是挺精简的,整个代码做了那些事情。

  • 使用 Java8 nashorn 加载新浪的 osslogin.js
  • 调用自己的计算 sp(sinapassword) 代码
  • 组装其他请求参数,发送 post 请求
  • 得到需要访问的几个 URL 列表(这里有一个 cookie 需要请求来生成)
  • 查看获取邮件的请求,模拟发起请求得到对应的 Json 数据

完整代码移步到

http://git.oschina.net/94fzb/fetch-sina-mail

© 著作权归作者所有

hibegin

hibegin

粉丝 33
博文 9
码字总数 5952
作品 2
江北
私信 提问
Android 使用自带的HttpClient进行https请求出现403的解决过程记录

出现的过程 最近在用程序模拟一个web站的https登录,然后进行一些后续操作的小玩意。先使用java程序写测试代码,测试通过移植到android。 java基于httpclient-4.3.1.jar开发。 android端使用...

atearsan
2014/03/05
6.7K
1
httpclient DNS cache问题解决办法

DNS缓存在操作系统和JDK内部已经实现了吧,一般不需要再由程序介入了。 the JVM will cache the dns information for me automatically after the first query 也就是说,httpclient去抓取每...

索隆
2012/05/28
959
0
HttpClient在多线程环境下踩坑总结

HttpClient在多线程环境下踩坑总结 问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态。 ...

优惠券发放
03/28
0
0
httpclient4.4 出现NoHttpResponseException的异常解决

httpclient4.4简单初始化httpclient的方式: 使用连接池初始化httpclient的方式: 但在测试过程中发现,有时候出现如下的异常,但重试一次就没有问题: 网上查了相关的报错信息,找到官网上的...

一路向北的兔斯基
2015/07/30
23K
2
Java HTTP 组件库选型看这篇就够了

原文出处:行思錄 Java HTTP 组件库选型看这篇就够了 最近项目需要使用 Java 重度调用 HTTP API 接口,于是想着封装一个团队公用的 HTTP client lib. 这个库需要支持以下特性: 连接池管理,...

行思錄
2018/09/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

好程序员大数据教程Scala系列之样例类_Option_偏函数

  好程序员大数据教程Scala系列之样例类_Option_偏函数,在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值。 ...

好程序员官网
24分钟前
4
0
zk中ServerCnxnFactory连接管理工厂

作为ServerCnxn的工厂抽象类 属性 ZOOKEEPER_SERVER_CNXN_FACTORY zookeeper.serverCnxnFactory secure 在ServerCnxnFactory中SSL是否启用 sessionMap session管理配置中信息(sessionId,Ser......

writeademo
25分钟前
5
0
【代码审计01】几种常见的漏洞种类以及代码审计工具

前言 代码审计是在经过黑盒测试完毕,也就是检查应用的基本功能是否符合产品业务需求下进行的。需要有一定的编码基础以及对漏洞形成原理的基本认知,通过工具或者经验检测代码中可能出现的b...

北桥苏
26分钟前
4
0
重磅发布 | 全球首个云原生应用标准定义与架构模型 OAM 正式开源

作者: OAM 项目负责人 导读:2019 年 10 月 17 日,阿里巴巴合伙人、阿里云智能基础产品事业部总经理蒋江伟(花名:小邪)在 Qcon 上海重磅宣布,阿里云与微软联合推出开放应用模型 Open A...

阿里巴巴云原生
28分钟前
3
0
【进阶之定义函数】一个查询树结构数据的集合

1、基本定义 delimiter 自定义符号  -- 如果函数体只有一条语句, begin和end可以省略, 同时delimiter也可以省略create function 函数名(形参列表) returns 返回类型  -- 注意是retru...

卯金刀GG
34分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部