这个题目,讲真,我也奇怪,我为什么写个爬虫需要用到这种大型框架,最开始,刚开始接触爬虫的时候,我写的爬虫,只要能获得我想要的数据,那就是成功的,完美的,没有bug的,哪怕他慢,哪怕操作繁琐且复杂,只要获取我想要的数据,那就是成功的。

后来,闲来无事,Java用习惯了,不想重新用Python写爬虫了,怎么办呢,Java写呗,反正都是case by case的,其实在写这个爬虫的时候,我不止一次的问自己,写代码的时间,估计你自己手动都能下载完了吧。

写了两个case,一个是爬取mm131网站的,这个难度不大,因为不需要登录状态,服务器也不需要检测请求频率,不过我还是把IP伪装了一下,20个线程跑满直接抓取,中间出了点小插曲,就是这个网站在我已经爬取完一次存了十几个G图片的之后一两天,也不知道是新配置的nginx,还是出了问题,动不动就爆403,但是仔细看了看,问题不大,失败了强制刷新,多刷新几次就可以了,所以直接暴力在catch里面做了迭代调用,不过效果还可以。有兴趣的话可以下载看看,工程比较简单,只需要修改配置文件,创建一个放置图片的文件夹就可以直接爬取,有兴趣可以clone下来看看https://github.com/gsy44355/mm131pic.git

第二个case是我抓新浪博客的,这个真的是,头大。背景呢,是由于我关注的一个博主实在是太高产了,导致我根本没办法下载所有原图,哪有那么多时间刷微博啊= =,所以想着写个爬虫一次性爬取完所有的图片,这样就省事多了。但是新浪毕竟是大公司,所以啊,之前开20个线程爬取,一直会报错,报错都是未授权,这种未授权的错误,千万不能强行持续重传,会导致自己账号cookie被封,我被封了两次cookie,还改了一次密码= = 真担心自己号没了。

那么该如何爬取呢?首先,要保证速度Thread.sleep(1000),就可以了,那好,加个这个,然后重新爬取。。诶,刚下载了两个图片,凉了,又是405报错。。。我于是痛定思痛,是什么问题呢?其实出在每一次如果只用内存保存链接,会导致这次失败了,又去做一次无用功。好嘛,mybatis+MySQL,顺便也加个log吧,自己试了几分钟以后发现,还是springboot简单,整合,直接使用就是了,哪有那么复杂。

附上Crawlerbase类,WeiboCrawler类供大家参考,提出建议,因为base类希望能够尽可能的设计通用,详细的代码可以clone https://github.com/gsy44355/springboot-start.git,我应该会把这个维护起来的,不过这个工程内容比较多,不适合单独研究爬虫,不过可以直接用Test来运行你想运行的代码,目前启动速度还是在秒级的。

package com.gsy.springboot.start.serviceImpl;import com.gsy.springboot.start.mapper.TbCrawlerUrlCustomMapper;
import com.gsy.springboot.start.mapper.auto.TbCrawlerUrlMapper;
import com.gsy.springboot.start.pojo.TbCrawlerUrl;
import com.gsy.springboot.start.service.CrawlerBaseService;
import com.gsy.springboot.start.util.LogUtil;
import com.gsy.springboot.start.util.crawler.CrawlerSpecialFunc;
import com.gsy.springboot.start.util.crawler.CreateHeaderMap;
import com.gsy.springboot.start.util.crawler.WebCrawlerUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** Created By Gsy on 2019/5/18*/
@Service
public class CrawlerBaseServiceImpl implements CrawlerBaseService {@AutowiredTbCrawlerUrlMapper tbCrawlerUrlMapper;@AutowiredTbCrawlerUrlCustomMapper tbCrawlerUrlCustomMapper;@Overridepublic synchronized String getUrl(String type) {TbCrawlerUrl tbCrawlerUrl = tbCrawlerUrlCustomMapper.getOneUrl(type);if (tbCrawlerUrl == null){return null;}tbCrawlerUrl.setBusy("1");tbCrawlerUrlMapper.updateByPrimaryKeySelective(tbCrawlerUrl);return tbCrawlerUrl.getUrl();}@Overridepublic int updateUrlToNoUse(String url) {return tbCrawlerUrlMapper.updateByPrimaryKeySelective(new TbCrawlerUrl(url,"0"));}@Overridepublic int addUrl(TbCrawlerUrl tbCrawlerUrl) {try{return tbCrawlerUrlMapper.insertSelective(tbCrawlerUrl);}catch (DuplicateKeyException e){LogUtil.info(this.getClass(),"Crawler获取到重复Url={}",tbCrawlerUrl.getUrl());return 1;}}@Overridepublic int deleteUrl(String url) {return tbCrawlerUrlMapper.deleteByPrimaryKey(url);}@Overridepublic int deleteAll() {return tbCrawlerUrlCustomMapper.deleteAll();}@Overridepublic void doCrawler(String type,long sleepTime,CrawlerSpecialFunc crawlerSpecialFunc) {int errorCount = 0;while(true){String url = null;try {if(sleepTime != 0 ){Thread.sleep(sleepTime);}url = this.getUrl(type);if(url == null){break;}LogUtil.info(this.getClass(),"获取到Url={}",url);crawlerSpecialFunc.specialFunc(url);this.deleteUrl(url);}catch (Exception e){errorCount++;LogUtil.error(this.getClass(),"抓取异常,决定需要如何处理",e);this.updateUrlToNoUse(url);if (errorCount >100){break;}}}}
}

下面是case by case 的微博爬虫,startNew 和 reStart就是两个入口方法。

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

尴尬的修改了一次,发现这玩意竟然不能直接多线程操作- -

package com.gsy.springboot.start.serviceImpl;import com.gsy.springboot.start.pojo.TbCrawlerUrl;
import com.gsy.springboot.start.service.CrawlerBaseService;
import com.gsy.springboot.start.service.WeiboCrawlerService;
import com.gsy.springboot.start.util.LogUtil;
import com.gsy.springboot.start.util.crawler.CreateHeaderMap;
import com.gsy.springboot.start.util.crawler.WebCrawlerUtil;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;/*** Created By Gsy on 2019/5/18*/
@Service
@EnableAsync
public class WeiboCrawlerServiceImpl implements WeiboCrawlerService {@AutowiredCrawlerBaseService crawlerBaseService;@Overridepublic void startNew() {crawlerBaseService.deleteAll();ResourceBundle resourceBundle = ResourceBundle.getBundle("crawler/start");for (int i = Integer.parseInt(resourceBundle.getString("countStart") ); i <Integer.parseInt(resourceBundle.getString("countEnd") ); i++) {crawlerBaseService.addUrl(new TbCrawlerUrl(resourceBundle.getString("mainUrl").replace("@replace@",""+i),"1","0"));}reStart();}@Overridepublic void reStart() {getUrl();getPicUrl();List<Thread> list = new ArrayList<>();for (int i = 0; i < 20; i++) {LogUtil.info(this.getClass(),"创建线程={}",""+i);Thread thread = new Thread(() -> getPic());list.add(thread);thread.start();}for (Thread thread:list) {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}}}/*** 获取图片源链接,会有两种方式  针对的是https://weibo.cn*/public void getUrl() {crawlerBaseService.doCrawler("1",1000,(s) -> {String html = WebCrawlerUtil.getWebHtml(s, CreateHeaderMap.getMapByName("crawler/page"),"utf-8");Document document = Jsoup.parse(html);Elements elements = document.getElementsByTag("a");for (Element e : elements) {String url = e.attr("href");if (url.matches(".*?picAll.*?")) {crawlerBaseService.addUrl(new TbCrawlerUrl(url,"1","0"));LogUtil.info(this.getClass(),"存入的AllUr={}" + url);} else if (url.matches(".*?oripic.*?")) {if(!s.matches("https://weibo.cn/u/6697930990[?]filter=2&page=\\d+")){url = "https://weibo.cn"+url;}crawlerBaseService.addUrl(new TbCrawlerUrl(url,"2","0"));LogUtil.info(this.getClass(),"存入的Url={}" + url);}}});}/*** 获取图片真实链接,进行了一次302跳转*/public void getPicUrl(){crawlerBaseService.doCrawler("2",1000,(url) -> {String picUrl = WebCrawlerUtil.get302Location(url,CreateHeaderMap.getMapByName("crawler/picR"));if(StringUtils.isNotEmpty(picUrl)){crawlerBaseService.addUrl(new TbCrawlerUrl(picUrl,"3","0"));}});}/*** 真实获取图片,这个没有session,多线程随便跑*/@Asyncpublic void getPic() {crawlerBaseService.doCrawler("3",0,url -> {WebCrawlerUtil.getWebPicture(url, url.substring(url.lastIndexOf("/")), CreateHeaderMap.getMapByNameWithRandomIp("crawler/picture"), ResourceBundle.getBundle("crawler/start").getString("dir"));LogUtil.info(this.getClass(),"保存图片={}" + url);});}
}

后面整理好会维护文档和发布到github上,有什么问题可以留言讨论,希望指出我的不足。

Java爬虫 springboot框架下 新浪微博爬虫相关推荐

  1. 基于JAVA(Springboot框架)助农商城平台系统设计与实现 毕业设计开题报告

      本科生毕业论文 基于JAVA(Springboot框架)助农商城平台 开题报告 学    院: 专    业: 计算机科学与技术 年    级: 学生姓名: 指导教师:   XXXX大学本科生毕业 ...

  2. scrapy框架下pythom爬虫的数据库(MYSQL)

    本次主要讲述在scrapy框架下pythom爬虫有关mysql数据库的相关内容. 首先在MySQL数据库中创建对应的表,注意字段的设计! 数据库的信息存在setting 里,数据信息host,data ...

  3. springboot框架下利用websocket实现即时通讯

    springboot框架下利用websocket实现即时通讯(文章末尾有git项目打包文件,直接下载使用即可) 用websocket实现简单的在线聊天,先画个时序图,直观感受下流程 SystemCon ...

  4. SpringBoot框架下使用Servlet

    SpringBoot框架下使用Servlet 创建一个Servlet继承HttpServlet 在web.xml配置文件中使用servlet servlet-mapping 1. 第一种方式:注解的方 ...

  5. java 自动装载_java_详解Java的Spring框架下bean的自动装载方式,Spring容器可以自动装配相互协 - phpStudy...

    详解Java的Spring框架下bean的自动装载方式 Spring容器可以自动装配相互协作bean之间的关系,这有助于减少对XML配置,而无需编写一个大的基于Spring应用程序的较多的和元素. 自 ...

  6. ProxyPool proxy-pool: java 基于springboot框架获取代理ip

    PROXY-POOL: java 基于springboot框架获取代理ip

  7. 基于SpringBoot框架Wbe Magic爬虫框架爬取招聘信息项目(1)

    涉及的技术点:SpringBoot框架.Web Magic爬⾍框架.MySQL.mybatis. 使用语言:Java. 使用工具:idea. 本篇文章主要讲解搭建项目 以及 如何将页面数据输出打印到i ...

  8. springboot框架下的实时消息推送

    功能实现:在得到新数据后以最快的速度推送到前台.(springboot框架) 0.修改pom文件 加入需要的jar包 <dependency><groupId>org.spri ...

  9. 基于Java后台(Springboot框架)+前端小程序(MINA框架)+Mysql数据库的教室图书馆座位预约小程序系统设计与实现

    项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于微信小程序预约订座小程序,前台用户使用小程序,后台管理使用Java+Mysql开发,后台使用了springboot框架:通过后台添加座位类型 ...

最新文章

  1. Windows10 搭建java环境——JDK11的安装与eclipse的安装
  2. nginx常用功能全揭秘
  3. 002_JavaScript的历史
  4. 雷蛇鼠标宏文件_《硬事要说34》稳接曼巴的旗?雷蛇巴塞利斯蛇[终极版]解读...
  5. linux命令之有关关机和查看系统信息的命令
  6. jsp页面跳转(商品管理系统)
  7. 一个IO的传奇一生 (9) -- Noop和Deadline调度器
  8. 父元素没有高度,子元素高度失效
  9. python实现匿名发邮件_python 发送匿名邮件或无发件人
  10. 漏洞解决方案-敏感信息脱敏显示
  11. 阿里云解析是什么?个人版和企业版有什么区别?
  12. 互联网晚报 |11/23星期三 | 京东高管降薪10%至20%;75%未成年每周游戏少于3小时;惠普宣布未来三年裁员4K-6K人...
  13. 爱学习的小虫子——Who Am I ?
  14. OSPF中双ASBR重发布5类LSA问题
  15. Angular cdk 学习之 Bidirectionality(bidi)
  16. 蓝桥杯单片机——串口通信1(11)
  17. SQL中对 datetime 类型操作
  18. 统计学简介之十六——单因素方差分析
  19. 项目经理需要的基本技能
  20. javaweb三大框架

热门文章

  1. 华为云园区网络四大升级;IMAX中国十一黄金周劲收1.68亿票房;电通集团推出综合解决方案电通游戏 | 全球TMT...
  2. 词性标注pos_tagging
  3. RTL8762DW手环SDK创建哪些任务
  4. 我有必要给英语学习做个笔记了
  5. 网易云音乐歌手歌曲、用户评论、用户信息爬取
  6. mpvue 未找到app.json入口文件
  7. abap 会计凭证过账(BAPI_ACC_DOCUMENT_POST)非资产过账填写资产号写不进去
  8. 载波聚合或双连接的方式进行_现有智能手机能否实现双4g网络聚合,从而实现网络加速?...
  9. Python 之父:因打发时间创造 Python,躬耕多年退位
  10. 看漫画学电子,非常精彩!有些概念以前模糊,现在真的懂了