前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA自动爬取CSDN用户数据并文章点赞

JAVA自动爬取CSDN用户数据并文章点赞

作者头像
逝兮诚
发布2019-10-30 20:07:31
8000
发布2019-10-30 20:07:31
举报
文章被收录于专栏:代码人生代码人生

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/luo4105/article/details/87166231

爬取用户

某天,我发现我的文章被某个用户点赞了。欣喜之下,把那边文章重新校核更改一遍,接着进入这个点赞我的用户看看,结果发现他近期的博客是一些爬虫的实战。我想,我那篇文章,应该是他做的一个小程序批量加载用户信息并给文章点赞。我觉得这是一个有点意思的事,于是用java实现csdn批量爬取用户名并点赞。

题外话到此为止,先说说怎么获得csdn的用户名的,他的方法是通过用户的粉丝和关注两个列表,最多可以获得12个用户名,再根据这12个用户名,继续进入每个用户的主页,获得该用户的粉丝和关注列表的用户数据,这样无限循环往复,直到找到很多很多的用户名。

1.通过https://me.csdn.net/用户名获得粉丝和关注列表。

在这里插入图片描述
在这里插入图片描述

2.查看页面源码,用正则匹配

代码语言:javascript
复制
<a class="fans_title" href="https://me.csdn.net/qq_33981796">qq_33981796</a>

匹配正则

代码语言:javascript
复制
a class="fans_title" href="https://me.csdn.net/(.+)"

3.获得匹配的用户名,再次进入https://me.csdn.net/用户名页面,重复1,2的操作

代码

代码语言:javascript
复制
    public Set<String> users = new HashSet<>();
    
    public void getCSDNUsers(String userName) {
        if (users.size() > 30) {
            return;
        }
        Set<String> userList = parseFans(mePage(userName));
        if (userList != null && userList.size() > 0) {
            synchronized (users) {
                users.addAll(userList);
            }
            userList.stream().forEach(user -> getCSDNUsers(user, token));
        }
    }
代码语言:javascript
复制
    public String mePage(String username) {
        String follerUrl = "https://me.csdn.net/" + username;
        try {
            Map<String, String> headers = new HashMap<>();
            headers.put("cook", "UserName=luo4105; UserInfo=de5e709f7cd84e2d87648d45e6288db0; " +
                    "UserToken=de5e709f7cd84e2d87648d45e6288db0;");
            InputStream inputStream = HttpUtil.doGet(follerUrl, headers);
            String response = StreamUtil.inputStreamToString(inputStream, "UTF-8");
            return response;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
代码语言:javascript
复制
    public Set<String> parseFans(String pageContext) {
        if (pageContext == null || pageContext.length() == 0) {
            return new HashSet<>();
        }
        String fansRegex = "a class=\"fans_title\" href=\"https://me.csdn.net/(.+)\"";
        Pattern pattern = Pattern.compile(fansRegex);
        Matcher matcher = pattern.matcher(pageContext);
        Set<String> fanses = new HashSet<>();
        while (matcher.find()) {
            fanses.add(matcher.group(1));
        }
        return fanses;
    }

这里只拉30个用户的数据,我也没有想好怎么截止这个任务。附上自己写的httpUtil和StreamUtil的访问网页的方法并输出string的方法。

代码语言:javascript
复制
//httpUtil.doGet方法
    public static InputStream doGet(String urlstr, Map<String, String> headers) throws IOException {
        URL url = new URL(urlstr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 " +
                "(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36");
        conn.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp," +
                "image/apng,*/*;q=0" +
                ".8");
        if (headers != null) {
            Set<String> keys = headers.keySet();
            keys.stream().forEach(key -> {
                conn.setRequestProperty(key, headers.get(key));
            });
        }
        Random random = new Random();
        String ip =
                (random.nextInt(100) + 100) + "." + (random.nextInt(100) + 100) + "." + (random.nextInt(100) + 100) + "." + (random.nextInt(100) + 100);
        conn.setRequestProperty("x-forwarded-for", ip);
        InputStream inputStream = conn.getInputStream();

        return inputStream;
    }
代码语言:javascript
复制
public class StreamUtil {
    public static String inputStreamToString(InputStream is, String charset) throws IOException {
        byte[] bytes = new byte[1024];
        int byteLength = 0;
        StringBuffer sb = new StringBuffer();
        while ((byteLength = is.read(bytes)) != -1) {
            sb.append(new String(bytes, 0, byteLength, charset));
        }
        return sb.toString();
    }
}

博文点赞

分析一下博文点赞的API,随便打开一篇博客,并点赞,查看浏览器请求日志。

  1. Request URL: https://blog.csdn.net/u014633966/phoenix/article/digg?ArticleId=86526464
  2. Request Method: GET

cookie: UserName=luo4105; UserToken=xxxxxxxxxxxx; 只要拿到ArticleId,自己的UserToken,就可以拼接请求点赞博客了。

大致思路是这样的,打开https://me.csdn.net/用户名博客主页,解析文章列表便可获得文章id。跟踪登陆API,查看请求参数和响应中的cook的插入,解析出token。有了这些参数,就可以拼点赞请求了。

获得用户下的ArticleId

为了防止一下子把羊毛褥完了,我这里拿的是每个用户下的第一篇aritcleId,思路是这样的。

1.进入该用户的默认博客列表页面

这里通过https://blog.csdn.net/用户名/article/list/1进入博客列表

2.通过正则匹配获得第一篇文章链接中的ArticleId和userName

页面代码

代码语言:javascript
复制
<a href="https://blog.csdn.net/luo4105/article/details/86599896" target="_blank">
        <span class="article-type type-1">
            原        </span>
        Could not set parameters for mapping错误与mybatis源码追踪      </a>

实现代码

代码语言:javascript
复制
    public Map<String, String> getFirstArticleId(Set<String> userNames) {
        Map<String, String> articleIdMap = new HashMap<>();
        String blogUrlTemplate = "https://blog.csdn.net/%s/article/list/1";
        userNames.stream().forEach(userName -> {
            String blogUrl = String.format(blogUrlTemplate, userName);
            try {
                InputStream inputStream = HttpUtil.doGet(blogUrl);
                String content = StreamUtil.inputStreamToString(inputStream, "UTF-8");
                String articleIdRegex = "https://blog.csdn.net/" + userName + "/article/details/([0-9]{8})";
                Pattern pattern = Pattern.compile(articleIdRegex);
                Matcher matcher = pattern.matcher(content);
                while (matcher.find()) {
                    articleIdMap.put(userName, matcher.group(1));
                    break;
                }
            } catch (IOException e) {
                System.out.println("http get failed");
                e.printStackTrace();
            }
        });
        return articleIdMap;
    }
模拟登陆获得token

使用浏览器查看csdn登陆请求,分析request和response,找到接口url,请求格式,用户名和密码在哪里传的,token在哪里返回的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过查看csdn登陆请求可知道

  1. 登陆接口url是https://passport.csdn.net/v1/register/pc/login/doLogin,method是POST,content-type是application/json;charset=UTF-8
  2. 参数和密码通过一个json字符串上传,json格式是{loginType: "1", pwdOrVerifyCode: "xx", userIdentification: "xxx",...},关键参数是pwdOrVerifyCode(密码)和userIdentification(账号)。
  3. token是通过response的header存入cookie,可通过拿response的header获得登陆token。

实现代码

代码语言:javascript
复制
    /**
     * 模拟登陆,并从cookie中拿出token和用户名
     *
     * @param username
     * @param password
     */
    public UserToken login(String username, String password) {
        String url = "https://passport.csdn.net/v1/register/pc/login/doLogin";
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("accept", "application/json;charset=UTF-8");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("loginType", "1");
        jsonObject.put("pwdOrVerifyCode", password);
        jsonObject.put("userIdentification", username);
        UserToken userToken = new UserToken();
        try {
            Map<String, List<String>> repHeaders = HttpUtil.doPostJSON(url, headers,
                    jsonObject.toJSONString());
            List<String> setCookies = repHeaders.get("Set-Cookie");
            if (setCookies != null && setCookies.size() > 0) {
                setCookies.stream().forEach(cook -> {
                    if (cook.contains("UserToken=")) {
                        String userTokenRegex = "UserToken=(.*); Max";
                        Pattern pattern = Pattern.compile(userTokenRegex);
                        Matcher matcher = pattern.matcher(cook);
                        while (matcher.find()) {
                            userToken.setToken(matcher.group(1));
                        }
                    }
                    if (cook.contains("UserName=")) {
                        String userTokenRegex = "UserName=(.*); Max";
                        Pattern pattern = Pattern.compile(userTokenRegex);
                        Matcher matcher = pattern.matcher(cook);
                        while (matcher.find()) {
                            userToken.setUserName(matcher.group(1));
                        }
                    }
                });
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return userToken;
    }

    @Data
    public static class UserToken {
        private String token;
        private String userName;
    }

以上,就是csdn自动爬取用户并给文章点赞的实现方式和过程。

整个项目源代码已经上传github,欢迎大家下载使用并改进,https://github.com/programluo/csdn-tool

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-02-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 爬取用户
  • 博文点赞
    • 获得用户下的ArticleId
      • 模拟登陆获得token
      相关产品与服务
      云开发 CloudBase
      云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档