java 爬虫 抓取网上的图片报错521解决方案

最近做爬虫时碰到了521错误,500开头的都是服务器错误;521错误码需要请求多次才能返回正确的结果;查看请求次数需要借助抓包工具,我自己使用Fiddler 4抓取到发送了三次请求才拿到结果,所以这就需要我们解析三次请求了。

1、Fiddler 抓取结果两次521、1次200拿到了结果,这就意味着我们需要提交三次请求才能拿到结果。

2、根据抓包看到必须三次请求才能拿到结果,我们逐一解析每次请求和响应。下面是正确拿到结果的请求头,红框内的cookie是重点。

        1)、我们使用postman发送第一次请求,得到响应头Set-Cookie中的

__jsluid_s=ed2b28b0b03114218d2b0e03a1b56f12,此参数在第二次,第三次请求时加入cookie中(两次请求中此参数值保持不变);还有另一个参数就是返回值js代码(返回值中的js也可以在html中打印出来),使用ScriptEngineManager处理两个红竖杠中的js;得到__jsl_clearance_s=1628664214.493|-1|cx9ymjyfz6PzeXeREg6KcTa7P24%3D;(它后面的代码不需要)

    

         2)、将__jsluid_s和__jsl_clearance_s放入到cookie中再次发送请求,会得到返回值是一大串js代码,跟第一次的返回值不一样,这个又多又乱,看到下图中的代码眼晕吧

扫描二维码关注公众号,回复: 17327897 查看本文章

        别慌,咱们看重点,将返回值拉到最后,两个红竖杠之间才是我们想要的,所以上面那么一大堆代码我们可以不用管它;直接看重点,仔细看看这段是不是有点眼熟,这就是解密的关键。

        首先我们看bts对象,是不是很像__jsl_clearance_s参数值,没错,这就是第三次请求的cookies参数的部分值(是一大部分),chars,ct,ha这几个对象是解密的关键,chars是随机的字母,ha是加密算法(MD5,sha1,sha256三种算法),ct是加密的结果,看到这,各位应该想到了解析方式;我们可以对比标准的数据__jsl_clearance_s=1628662388.812|0|nzqTL5FJzLGZp%2BuNyQfckpBkghQ%3D

__jsl_clearance_s = (bts数组1)+(chars随机两个字母)+(bts数组2),

这就是第二个参数值

        3)、根据第一次得到的不变参数__jsluid_s与第二次得到的__jsl_clearance_s在次发送请求,就能拿到结果了。

3、最后,我将我自己的代码贴上来,供大家参考;提醒:在第二次请求解析__jsl_clearance_s参数的方式不一定能使用到什么时候,如果过段时间他们更新了其他加密方法,就需要各位自行处理了。

============================  

/**
 * cookie参数
 */
private static String JSL_UID = "";

/**
 * cookie参数
 */
private static String JSL_CLEARANCE = "";
/**
* @Description 抓取网上的图片
* @Author  lqt
* @Date   2021/8/4
* @Param imgSrc 图片路径
* @Param www 域名地址
* @Return
* @Exception
*/
public static void downloadImgByNet(String imgSrc,String www) {
    CloseableHttpClient client = null;
    ​​​​​​​CloseableHttpResponse response = null;
    try {
        //设置https协议访问
        System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2,SSLv3");
        // 发送请求
        client = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(TIME_OUT)
                .setSocketTimeout(TIME_OUT).setConnectTimeout(TIME_OUT).build();
        HttpGet get = new HttpGet(imgSrc);
        get.setConfig(requestConfig);
        //模拟浏览器
        get.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
        get.setHeader("Accept-Encoding", "gzip, deflate, br");
        get.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
        get.setHeader("Cache-Control", "no-cache");
        get.setHeader("Connection", "keep-alive");
        get.setHeader("Host", www);
        get.setHeader("Cookie", JSL_UID + ";" + JSL_CLEARANCE);
        get.setHeader("Pragma", "no-cache");
        get.setHeader("sec-ch-ua", "Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91");
        get.setHeader("sec-ch-ua-mobile", "?0");
        get.setHeader("Sec-Fetch-Dest", "document");
        get.setHeader("Sec-Fetch-Mode", "navigate");
        get.setHeader("Sec-Fetch-Site", "none");
        get.setHeader("Sec-Fetch-User", "?1");
        get.setHeader("Upgrade-Insecure-Requests", "1");
        get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36");
        response = client.execute(get);
        // 第一次请求响应头中的,在第二次第三次请求需要带此参数
        String jsluid_s = "";
        // 第二次请求 带入 __jsluid_s 与 __jsl_clearance_s
        if (response.getStatusLine().getStatusCode() == HTTP_521) {
            System.out.println("错误-521");
            Header[] hs = response.getHeaders("Set-Cookie");
            if(Objects.isNull(hs) || hs.length < 1){
                System.out.println("获取Set-Cookie错误");
                downloadImgByNet(imgSrc,filePath,fileName,www,"");
            }
            jsluid_s = "__jsluid_s=" + hs[0].toString().split(";")[0].split("=")[1];
            HttpEntity entity = response.getEntity();
            String resHtml = EntityUtils.toString(entity);
            // 对返回js处理 拿到jsl_clearance
            String jsl_clearance_s = getJslClearance(resHtml);
            get.setHeader("Cookie", jsluid_s + ";" + jsl_clearance_s);
            response = client.execute(get);
        }

        // 第三次请求 带入 __jsluid_s 与 __jsl_clearance_s(重新计算得到的与第二次不同)
        if (response.getStatusLine().getStatusCode() == HTTP_521) {
            HttpEntity entity = response.getEntity();
            String resHtml = EntityUtils.toString(entity);
            // 对返回js处理 拿到jsl_clearance
            resHtml = resHtml.substring(resHtml.lastIndexOf("go(") + 3, resHtml.lastIndexOf(")"));
            JSONObject data = JSON.parseObject(resHtml);
            String jsl_clearance_s = go(data);
            JSL_UID = jsluid_s;
            JSL_CLEARANCE = jsl_clearance_s;
            get.setHeader("Cookie", jsluid_s + ";" + jsl_clearance_s);
            response = client.execute(get);
        }

        // 输出文件
        if (response.getStatusLine().getStatusCode() == HttpStatus.HTTP_OK) {
            //拿到最终想要的页面
            HttpEntity entity = response.getEntity();
            if(!Objects.isNull(entity)){
                String s = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
            }
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        try {if(response != null) {response.close();}} catch (IOException e) {e.printStackTrace();}
    }
}
/**
* @Description 将第一次返回js数据转换
* @Author  lqt
* @Date   2021/8/3
* @Param body js文件
* @Return
* @Exception
*/
private static String getJslClearance(String body){
    String jsl_clearance = "";
    ScriptEngineManager manager = new ScriptEngineManager();
    //得到脚本引擎
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    //处理加密js
    String js = body.trim().replace("<script>", "")
            .replace("</script>", "")
            .replace("document.cookie=", "")
            .replace("location.href=location.pathname+location.search", "");
    try {
        //得到解密后的js
        String result = (String) engine.eval(js);
        jsl_clearance = result.split(";")[0];
    } catch (ScriptException e) {
        e.printStackTrace();
    }
    return jsl_clearance;
}

/**
* @Description 处理第二次返回js数据
* @Author  lqt
* @Date   2021/8/3
* @Param data go对象
* @Return
* @Exception
*/
private static String go(JSONObject data) {
    String[] bts = data.getObject("bts",String[].class);
    String ct = data.getString("ct");
    String[] chars = data.getString("chars").split("");
    String ha = data.getString("ha");
    for (int i = 0; i < chars.length; i ++){
        for (int j = 0; j < chars.length; j ++){
            String i1 = chars[i];
            String j1 = chars[j];
            String cookie = bts[0] + i1 + j1 + bts[1];
            if (Objects.equals(hash(cookie,ha),ct)) {
                return "__jsl_clearance_s=" + cookie;
            }
        }
    }
    return "";
}
/**
* @Description 匹配加密  sha1,sha256,md5
* @Author  lqt
* @Date   2021/8/3
* @Param  cookie需要加密的字符串
* @Param ha 加密类型
* @Return
* @Exception
*/
private static String hash(String cookie, String ha){
    String str = "";
    try {
        switch (ha){
            case "sha1":str = HeaUtil.sha1(cookie);break;
            case "sha256":str = HeaUtil.sha256(cookie);break;
            case "md5":str = HeaUtil.md5(cookie);break;
            default:break;
        }
        return str;
    }catch (Exception e){
        e.printStackTrace();
    }
    return str;
}

============== 下面代码为工具类

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* @Description HeaUtil
* Hash encryption algorithm
* 哈希加密算法:MD5、SHA-1、SHA-256、HMAC-SHA-1、HMAC-SHA-256
* 需要导入 org.apache.commons.codec 包
* @Author  lqt
* @Date   2021/8/3
* @Param
* @Return
* @Exception
*/
@SuppressWarnings("WeakerAccess")
public class HeaUtil {

    /**
     * md5加密
     *
     * @param text 内容
     * @return digest 摘要
     * @throws NoSuchAlgorithmException e
     */
    public static String md5(String text) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        byte[] bytes = messageDigest.digest(text.getBytes());
        return Hex.encodeHexString(bytes);
    }

    /**
     * sha1加密
     *
     * @param text 内容
     * @return digest 摘要
     * @throws NoSuchAlgorithmException e
     */
    public static String sha1(String text) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
        byte[] bytes = messageDigest.digest(text.getBytes());
        return Hex.encodeHexString(bytes);
    }

    /**
     * sha256加密
     *
     * @param text 内容
     * @return digest 摘要
     * @throws NoSuchAlgorithmException e
     */
    public static String sha256(String text) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] bytes = messageDigest.digest(text.getBytes());
        return Hex.encodeHexString(bytes);
    }

    /**
     * hmac-sha1加密
     *
     * @param text 内容
     * @param key 密钥
     *
     * @return 密文
     * @throws Exception e
     */
    public static String hmacSha1(String text, String key) throws Exception {
        SecretKeySpec sk = new SecretKeySpec(key.getBytes(), "HmacSHA1");
        return hmacSha1(text, sk);
    }

    /**
     * hmac-sha1加密
     *
     * @param text 内容
     * @param sk 密钥
     *
     * @return 密文
     * @throws Exception e
     */
    public static String hmacSha1(String text, SecretKeySpec sk) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(sk);
        byte[] rawHmac = mac.doFinal(text.getBytes());
        return new String(Base64.encodeBase64(rawHmac));
    }

    /**
     * 生成 HmacSha1 密钥
     *
     * @param key 密钥字符串
     * @return SecretKeySpec
     */
    public static SecretKeySpec createHmacSha1Key(String key) {
        return new SecretKeySpec(key.getBytes(), "HmacSHA1");
    }

    /**
     * hmac-sha256加密
     *
     * @param text 内容
     * @param key 密钥
     *
     * @return 密文
     * @throws Exception e
     */
    public static String hmacSha256(String text, String key) throws Exception {
        SecretKeySpec sk = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        return hmacSha1(text, sk);
    }

    /**
     * hmac-sha256加密
     *
     * @param text 内容
     * @param sk 密钥
     *
     * @return 密文
     * @throws Exception e
     */
    public static String hmacSha256(String text, SecretKeySpec sk) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(sk);
        byte[] rawHmac = mac.doFinal(text.getBytes());
        return new String(Base64.encodeBase64(rawHmac));
    }

    /**
     * 生成 HmacSha256 密钥
     *
     * @param key 密钥字符串
     * @return SecretKeySpec
     */
    public static SecretKeySpec createHmacSha256Key(String key) {
        return new SecretKeySpec(key.getBytes(), "HmacSHA256");
    }

    /**
     * 测试
     *
     * @param args args
     */
    public static void main(String[] args) throws Exception {
        String s = "123456789了踩踩踩";
        System.out.println(md5(s));
        System.out.println(sha1(s));
        System.out.println(sha256(s));
        String k = "ada232@12";
        System.out.println(hmacSha1(s, k));
        s = "aeqnfoavneornqoenr1啊可是到了南方情况无法弄清了我呢010jownfasdfqijqor";
        System.out.println(hmacSha1(s, k));
        SecretKeySpec sk1 = createHmacSha1Key(k);
        System.out.println(hmacSha1(s, sk1));
        SecretKeySpec sk256 = createHmacSha256Key(k);
        System.out.println(hmacSha256(s, sk256));
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_39310051/article/details/119539658