博客搬家系列(三)-爬取博客园博客

╰半夏微凉° 2022-04-22 01:32 535阅读 0赞

博客搬家系列(三)-爬取博客园博客

一.前情回顾

博客搬家系列(一)-简介:https://blog.csdn.net/rico_zhou/article/details/83619152

博客搬家系列(二)-爬取CSDN博客:https://blog.csdn.net/rico_zhou/article/details/83619509

博客搬家系列(四)-爬取简书文章:https://blog.csdn.net/rico_zhou/article/details/83619538

博客搬家系列(五)-爬取开源中国博客:https://blog.csdn.net/rico_zhou/article/details/83619561

博客搬家系列(六)-爬取今日头条文章:https://blog.csdn.net/rico_zhou/article/details/83619564

博客搬家系列(七)-本地WORD文档转HTML:https://blog.csdn.net/rico_zhou/article/details/83619573

博客搬家系列(八)-总结:https://blog.csdn.net/rico_zhou/article/details/83619599

二.开干(获取文章URL集合)

爬取博客园的博客思路跟CSDN一样,且下载图片那一步更为简单,任何header都不需要设置,同样,我们以ricozhou的主页为例分析源码https://www.cnblogs.com/ricozhou/

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70

我们可以看到文章列表如下,依然是很简洁的url,我们找一个博主文章较多的看看,方便分析规律,如https://www.cnblogs.com/xdp-gacl/

当我们点击下一页的时候,url如下

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 1

显然最后的2是页数,这样我们就找到了页面url规律,同样右击查看源码,分析找到文章都位于哪个标签内

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 2

观察发现,文章url均位于class为postTitle的标签内,代码如下:

  1. /**
  2. * @date Oct 17, 2018 12:30:46 PM
  3. * @Desc
  4. * @param blogMove
  5. * @param oneUrl
  6. * @return
  7. * @throws IOException
  8. * @throws MalformedURLException
  9. * @throws FailingHttpStatusCodeException
  10. */
  11. public void getCnBlogArticleUrlList(Blogmove blogMove, String oneUrl, List<String> urlList)
  12. throws FailingHttpStatusCodeException, MalformedURLException, IOException {
  13. // 模拟浏览器操作
  14. // 创建WebClient
  15. WebClient webClient = new WebClient(BrowserVersion.CHROME);
  16. // 关闭css代码功能
  17. webClient.getOptions().setThrowExceptionOnScriptError(false);
  18. webClient.getOptions().setCssEnabled(false);
  19. // 如若有可能找不到文件js则加上这句代码
  20. webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
  21. // 获取第一级网页html
  22. HtmlPage page = webClient.getPage(oneUrl);
  23. // System.out.println(page.asXml());
  24. Document doc = Jsoup.parse(page.asXml());
  25. Elements pageMsg = doc.select("div.postTitle");
  26. Element linkNode;
  27. for (Element e : pageMsg) {
  28. linkNode = e.select("a.postTitle2").first();
  29. if (linkNode == null) {
  30. continue;
  31. }
  32. if (urlList.size() < blogMove.getMoveNum()) {
  33. urlList.add(linkNode.attr("href"));
  34. } else {
  35. break;
  36. }
  37. }
  38. return;
  39. }

获取url集合如下

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 3

三.开干(获取文章具体信息)

同样,我们还是打开一篇博文,以使用爬虫框架htmlunit整合springboot出现的一个不兼容问题 为例,使用Chrome打开,我们可以看到一些基本信息,如文章的类型为原创,标题,时间,作者,阅读数,文章文字信息,图片信息等

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 4

2018110115560986.png

同样,右击查看源码找到对应的元素,然后获取内容

20181101155829105.png

2018110115583396.png

部分代码

  1. /**
  2. * @date Oct 17, 2018 12:46:52 PM
  3. * @Desc 获取详细信息
  4. * @param blogMove
  5. * @param url
  6. * @return
  7. * @throws IOException
  8. * @throws MalformedURLException
  9. * @throws FailingHttpStatusCodeException
  10. */
  11. public Blogcontent getCnBlogArticleMsg(Blogmove blogMove, String url, List<Blogcontent> bList)
  12. throws FailingHttpStatusCodeException, MalformedURLException, IOException {
  13. Blogcontent blogcontent = new Blogcontent();
  14. blogcontent.setArticleSource(blogMove.getMoveWebsiteId());
  15. // 模拟浏览器操作
  16. // 创建WebClient
  17. WebClient webClient = new WebClient(BrowserVersion.CHROME);
  18. // 关闭css代码功能
  19. webClient.getOptions().setThrowExceptionOnScriptError(false);
  20. webClient.getOptions().setCssEnabled(false);
  21. // 如若有可能找不到文件js则加上这句代码
  22. webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
  23. // 获取第一级网页html
  24. HtmlPage page = webClient.getPage(url);
  25. Document doc = Jsoup.parse(page.asXml());
  26. // 获取标题
  27. String title = BlogMoveCnBlogUtils.getCnBlogArticleTitle(doc);
  28. // 是否重复去掉
  29. if (blogMove.getMoveRemoveRepeat() == 0) {
  30. // 判断是否重复
  31. if (BlogMoveCommonUtils.articleRepeat(bList, title)) {
  32. return null;
  33. }
  34. }
  35. blogcontent.setTitle(title);
  36. // 获取作者
  37. blogcontent.setAuthor(BlogMoveCnBlogUtils.getCnBlogArticleAuthor(doc));
  38. // 获取时间
  39. if (blogMove.getMoveUseOriginalTime() == 0) {
  40. blogcontent.setGtmCreate(BlogMoveCnBlogUtils.getCnBlogArticleTime(doc));
  41. } else {
  42. blogcontent.setGtmCreate(new Date());
  43. }
  44. blogcontent.setGtmModified(new Date());
  45. // 获取类型
  46. blogcontent.setType(BlogMoveCnBlogUtils.getCnBlogArticleType(doc));
  47. // 获取正文
  48. blogcontent.setContent(BlogMoveCnBlogUtils.getCnBlogArticleContent(doc, blogMove, blogcontent));
  49. // 设置其他
  50. blogcontent.setStatus(blogMove.getMoveBlogStatus());
  51. blogcontent.setBlogColumnName(blogMove.getMoveColumn());
  52. // 特殊处理
  53. blogcontent.setArticleEditor(blogMove.getMoveArticleEditor());
  54. blogcontent.setShowId(DateUtils.format(new Date(), DateUtils.YYYYMMDDHHMMSSSSS));
  55. blogcontent.setAllowComment(0);
  56. blogcontent.setAllowPing(0);
  57. blogcontent.setAllowDownload(0);
  58. blogcontent.setShowIntroduction(1);
  59. blogcontent.setIntroduction("");
  60. blogcontent.setPrivateArticle(1);
  61. return blogcontent;
  62. }

详细信息

  1. /**
  2. * @date Oct 17, 2018 1:10:19 PM
  3. * @Desc 获取标题
  4. * @param doc
  5. * @return
  6. */
  7. public static String getCnBlogArticleTitle(Document doc) {
  8. // 标题
  9. Element pageMsg2 = doc.select("div#post_detail").first().select("h1.postTitle").first().select("a").first();
  10. return pageMsg2.ownText();
  11. }
  12. /**
  13. * @date Oct 17, 2018 1:10:28 PM
  14. * @Desc 获取作者
  15. * @param doc
  16. * @return
  17. */
  18. public static String getCnBlogArticleAuthor(Document doc) {
  19. Element pageMsg2 = doc.select("div.postDesc").first().select("a").first();
  20. return pageMsg2.ownText();
  21. }
  22. /**
  23. * @date Oct 17, 2018 1:10:33 PM
  24. * @Desc 获取时间
  25. * @param doc
  26. * @return
  27. */
  28. public static Date getCnBlogArticleTime(Document doc) {
  29. Element pageMsg2 = doc.select("div.postDesc").first().select("span#post-date").first();
  30. String date = pageMsg2.ownText().trim();
  31. // 这地方时间格式变化太多暂时不实现
  32. Date d = DateUtils.formatStringDate(date, DateUtils.YYYY_MM_DD_HH_MM_SS4);
  33. // 注意有些格式不正确
  34. return d == null ? new Date() : d;
  35. }
  36. /**
  37. * @date Oct 17, 2018 1:10:37 PM
  38. * @Desc 获取类型
  39. * @param doc
  40. * @return
  41. */
  42. public static String getCnBlogArticleType(Document doc) {
  43. // Element pageMsg2 =
  44. // doc.select("div.article-detail").first().select("h1.header").first().select("div.horizontal")
  45. // .first();
  46. // if ("原".equals(pageMsg2.html())) {
  47. // return "原创";
  48. // } else if ("转".equals(pageMsg2.html())) {
  49. // return "转载";
  50. // } else if ("译".equals(pageMsg2.html())) {
  51. // return "翻译";
  52. // }
  53. return "原创";
  54. }
  55. /**
  56. * @date Oct 17, 2018 1:10:41 PM
  57. * @Desc 获取正文
  58. * @param doc
  59. * @param object
  60. * @param blogcontent
  61. * @return
  62. */
  63. public static String getCnBlogArticleContent(Document doc, Blogmove blogMove, Blogcontent blogcontent) {
  64. Element pageMsg2 = doc.select("div#post_detail").first().select("div#cnblogs_post_body").first();
  65. String content = pageMsg2.toString();
  66. String images;
  67. // 注意是否需要替换图片
  68. if (blogMove.getMoveSaveImg() == 0) {
  69. // 保存图片到本地
  70. // 先获取所有图片连接,再按照每个链接下载图片,最后替换原有链接
  71. // 先创建一个文件夹
  72. // 先创建一个临时文件夹
  73. String blogFileName = String.valueOf(UUID.randomUUID());
  74. FileUtils.createFolder(FilePathConfig.getUploadBlogPath() + File.separator + blogFileName);
  75. blogcontent.setBlogFileName(blogFileName);
  76. // 匹配出所有链接
  77. List<String> imgList = BlogMoveCommonUtils.getArticleImgList(content);
  78. // 下载并返回重新生成的imgurllist
  79. List<String> newImgList = BlogMoveCommonUtils.getArticleNewImgList(blogMove, imgList, blogFileName);
  80. // 拼接文章所有链接
  81. images = BlogMoveCommonUtils.getArticleImages(newImgList);
  82. blogcontent.setImages(images);
  83. // 替换所有链接按顺序
  84. content = getCnBlogNewArticleContent(content, imgList, newImgList);
  85. }
  86. return content;
  87. }

代码共用,不再多放。还是一样的步骤,获取正文源码html匹配img,下载img,替换img链接,返回替换后的HTML

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 5

本人网站效果图:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JpY29femhvdQ_size_16_color_FFFFFF_t_70 6

欢迎交流学习!

完整源码请见github:https://github.com/ricozhou/blogmove​​​​​​​

发表评论

表情:
评论列表 (有 0 条评论,535人围观)

还没有评论,来说两句吧...

相关阅读

    相关 搬家

    博客搬家 因为linux相关的一些内容始终审核不过,而Linux和ros安装必须使用。所以造成了分享给朋友的不方便。所以搬家去了博客园。 地址 https://w