0x0 背景

最近学习爬虫,分析了几种主流的爬虫框架,决定使用最原始的两大框架进行练手:

Jsoup&HttpUnit

其中jsoup可以获取静态页面,并解析页面标签,最主要的是,可以采用类似于jquery的语法获取想要的标签元素,例如:

//1.获取url地址的网页html

html = Jsoup.connect(url).get();

// 2.jsoup获取新闻<a>标签

Elements newsATags = html.select("div#headLineDefault")

.select("ul.FNewMTopLis")

.select("li")

.select("a");

但是,有些网页(例如今日头条)并非是静态页面,而是在首页加载后通过ajax获取新闻内容然后用js渲染到页面上的。对于这种页面,我们需要使用htmlunit来模拟一个浏览器访问该url,即可获取该页面的html字符串。代码如下:

WebClient webClient = new WebClient(BrowserVersion.CHROME);

webClient.getOptions().setJavaScriptEnabled(true);

webClient.getOptions().setCssEnabled(false);

webClient.getOptions().setActiveXNative(false);

webClient.getOptions().setCssEnabled(false);

webClient.getOptions().setThrowExceptionOnScriptError(false);

webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);

webClient.getOptions().setTimeout(10000);

HtmlPage htmlPage = null;

try {

htmlPage = webClient.getPage(url);

webClient.waitForBackgroundJavaScript(10000);

String htmlString = htmlPage.asXml();

return Jsoup.parse(htmlString);

} finally {

webClient.close();

}

0x1 搜狐、凤凰、网易爬虫

这三家的页面都是静态的,因此代码都差不多,只要分析页面标签找到对应的元素,提取出想要的内容即可。

爬虫基本步骤为以下四步:

(1)获取首页

(2)使用jsoup获取新闻<a>标签

(3)从<a>标签中抽取基本信息,封装成News对象

(4)根据新闻url访问新闻页面,获取新闻内容、图片等

1.爬虫接口

一个接口,接口有一个抽象方法pullNews用于拉新闻,有一个默认方法用于获取新闻首页:

public interface NewsPuller {

void pullNews();

// url:即新闻首页url

// useHtmlUnit:是否使用htmlunit

default Document getHtmlFromUrl(String url, boolean useHtmlUnit) throws Exception {

if (!useHtmlUnit) {

return Jsoup.connect(url)

//模拟火狐浏览器

.userAgent("Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")

.get();

} else {

WebClient webClient = new WebClient(BrowserVersion.CHROME);

webClient.getOptions().setJavaScriptEnabled(true);

webClient.getOptions().setCssEnabled(false);

webClient.getOptions().setActiveXNative(false);

webClient.getOptions().setCssEnabled(false);

webClient.getOptions().setThrowExceptionOnScriptError(false);

webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);

webClient.getOptions().setTimeout(10000);

HtmlPage htmlPage = null;

try {

htmlPage = webClient.getPage(url);

webClient.waitForBackgroundJavaScript(10000);

String htmlString = htmlPage.asXml();

return Jsoup.parse(htmlString);

} finally {

webClient.close();

}

}

}

}

2.搜狐爬虫

@Component("sohuNewsPuller")

public class SohuNewsPuller implements NewsPuller {

private static final Logger logger = LoggerFactory.getLogger(SohuNewsPuller.class);

@Value("${news.sohu.url}")

private String url;

@Autowired

private NewsService newsService;

@Override

public void pullNews() {

logger.info("开始拉取搜狐新闻!");

// 1.获取首页

Document html= null;

try {

html = getHtmlFromUrl(url, false);

} catch (Exception e) {

logger.error("==============获取搜狐首页失败: {}=============", url);

e.printStackTrace();

return;

}

// 2.jsoup获取新闻<a>标签

Elements newsATags = html.select("div.focus-news")

.select("div.list16")

.select("li")

.select("a");

// 3.从<a>标签中抽取基本信息,封装成news

HashSet<News> newsSet = new HashSet<>();

for (Element a : newsATags) {

String url = a.attr("href");

String title = a.attr("title");

News n = new News();

n.setSource("搜狐");

n.setUrl(url);

n.setTitle(title);

n.setCreateDate(new Date());

newsSet.add(n);

}

// 4.根据新闻url访问新闻,获取新闻内容

newsSet.forEach(news -> {

logger.info("开始抽取搜狐新闻内容:{}", news.getUrl());

Document newsHtml = null;

try {

newsHtml = getHtmlFromUrl(news.getUrl(), false);

Element newsContent = newsHtml.select("div#article-container")

.select("div.main")

.select("div.text")

.first();

String title = newsContent.select("div.text-title").select("h1").text();

String content = newsContent.select("article.article").first().toString();

String image = NewsUtils.getImageFromContent(content);

news.setTitle(title);

news.setContent(content);

news.setImage(image);

newsService.saveNews(news);

logger.info("抽取搜狐新闻《{}》成功!", news.getTitle());

} catch (Exception e) {

logger.error("新闻抽取失败:{}", news.getUrl());

e.printStackTrace();

}

});

}

}

2.凤凰新闻爬虫

@Component("ifengNewsPuller")

public class IfengNewsPuller implements NewsPuller {

private static final Logger logger = LoggerFactory.getLogger(IfengNewsPuller.class);

@Value("${news.ifeng.url}")

private String url;

@Autowired

private NewsService newsService;

@Override

public void pullNews() {

logger.info("开始拉取凤凰新闻!");

// 1.获取首页

Document html= null;

try {

html = getHtmlFromUrl(url, false);

} catch (Exception e) {

logger.error("==============获取凤凰首页失败: {} =============", url);

e.printStackTrace();

return;

}

// 2.jsoup获取新闻<a>标签

Elements newsATags = html.select("div#headLineDefault")

.select("ul.FNewMTopLis")

.select("li")

.select("a");

// 3.从<a>标签中抽取基本信息,封装成news

HashSet<News> newsSet = new HashSet<>();

for (Element a : newsATags) {

String url = a.attr("href");

String title = a.text();

News n = new News();

n.setSource("凤凰");

n.setUrl(url);

n.setTitle(title);

n.setCreateDate(new Date());

newsSet.add(n);

}

// 4.根据新闻url访问新闻,获取新闻内容

newsSet.parallelStream().forEach(news -> {

logger.info("开始抽取凤凰新闻《{}》内容:{}", news.getTitle(), news.getUrl());

Document newsHtml = null;

try {

newsHtml = getHtmlFromUrl(news.getUrl(), false);

Elements contentElement = newsHtml.select("div#main_content");

if (contentElement.isEmpty()) {

contentElement = newsHtml.select("div#yc_con_txt");

}

if (contentElement.isEmpty())

return;

String content = contentElement.toString();

String image = NewsUtils.getImageFromContent(content);

news.setContent(content);

news.setImage(image);

newsService.saveNews(news);

logger.info("抽取凤凰新闻《{}》成功!", news.getTitle());

} catch (Exception e) {

logger.error("凤凰新闻抽取失败:{}", news.getUrl());

e.printStackTrace();

}

});

logger.info("凤凰新闻抽取完成!");

}

}

3.网易爬虫

@Component("netEasyNewsPuller")

public class NetEasyNewsPuller implements NewsPuller {

private static final Logger logger = LoggerFactory.getLogger(NetEasyNewsPuller.class);

@Value("${news.neteasy.url}")

private String url;

@Autowired

private NewsService newsService;

@Override

public void pullNews() {

logger.info("开始拉取网易热门新闻!");

// 1.获取首页

Document html= null;

try {

html = getHtmlFromUrl(url, false);

} catch (Exception e) {

logger.error("==============获取网易新闻首页失败: {}=============", url);

e.printStackTrace();

return;

}

// 2.jsoup获取指定标签

Elements newsA = html.select("div#whole")

.next("div.area-half.left")

.select("div.tabContents")

.first()

.select("tbody > tr")

.select("a[href~=^http://news.163.com.*]");

// 3.从标签中抽取信息,封装成news

HashSet<News> newsSet = new HashSet<>();

newsA.forEach(a -> {

String url = a.attr("href");

News n = new News();

n.setSource("网易");

n.setUrl(url);

n.setCreateDate(new Date());

newsSet.add(n);

});

// 4.根据url访问新闻,获取新闻内容

newsSet.forEach(news -> {

logger.info("开始抽取新闻内容:{}", news.getUrl());

Document newsHtml = null;

try {

newsHtml = getHtmlFromUrl(news.getUrl(), false);

Elements newsContent = newsHtml.select("div#endText");

Elements titleP = newsContent.select("p.otitle");

String title = titleP.text();

title = title.substring(5, title.length() - 1);

String image = NewsUtils.getImageFromContent(newsContent.toString());

news.setTitle(title);

news.setContent(newsContent.toString());

news.setImage(image);

newsService.saveNews(news);

logger.info("抽取网易新闻《{}》成功!", news.getTitle());

} catch (Exception e) {

logger.error("新闻抽取失败:{}", news.getUrl());

e.printStackTrace();

}

});

logger.info("网易新闻拉取完成!");

}

}

0x2 今日头条爬虫

由于今日头条页面中的新闻是通过ajax获取后加载的,因此需要使用httpunit进行抓取。

主要代码如下:

@Component("toutiaoNewsPuller")

public class ToutiaoNewsPuller implements NewsPuller {

private static final Logger logger = LoggerFactory.getLogger(ToutiaoNewsPuller.class);

private static final String TOUTIAO_URL = "https://www.toutiao.com";

@Autowired

private NewsService newsService;

@Value("${news.toutiao.url}")

private String url;

@Override

public void pullNews() {

logger.info("开始拉取今日头条热门新闻!");

// 1.load html from url

Document html = null;

try {

html = getHtmlFromUrl(url, true);

} catch (Exception e) {

logger.error("获取今日头条主页失败!");

e.printStackTrace();

return;

}

// 2.parse the html to news information and load into POJO

Map<String, News> newsMap = new HashMap<>();

for (Element a : html.select("a[href~=/group/.*]:not(.comment)")) {

logger.info("标签a: \n{}", a);

String href = TOUTIAO_URL + a.attr("href");

String title = StringUtils.isNotBlank(a.select("p").text()) ?

a.select("p").text() : a.text();

String image = a.select("img").attr("src");

News news = newsMap.get(href);

if (news == null) {

News n = new News();

n.setSource("今日头条");

n.setUrl(href);

n.setCreateDate(new Date());

n.setImage(image);

n.setTitle(title);

newsMap.put(href, n);

} else {

if (a.hasClass("img-wrap")) {

news.setImage(image);

} else if (a.hasClass("title")) {

news.setTitle(title);

}

}

}

logger.info("今日头条新闻标题拉取完成!");

logger.info("开始拉取新闻内容...");

newsMap.values().parallelStream().forEach(news -> {

logger.info("===================={}====================", news.getTitle());

Document contentHtml = null;

try {

contentHtml = getHtmlFromUrl(news.getUrl(), true);

} catch (Exception e) {

logger.error("获取新闻《{}》内容失败!", news.getTitle());

return;

}

Elements scripts = contentHtml.getElementsByTag("script");

scripts.forEach(script -> {

String regex = "articleInfo: \\{\\s*[\\n\\r]*\\s*title: '.*',\\s*[\\n\\r]*\\s*content: '(.*)',";

Pattern pattern = Pattern.compile(regex);

Matcher matcher = pattern.matcher(script.toString());

if (matcher.find()) {

String content = matcher.group(1)

.replace("&lt;", "<")

.replace("&gt;", ">")

.replace("&quot;", "\"")

.replace("=", "=");

logger.info("content: {}", content);

news.setContent(content);

}

});

});

newsMap.values()

.stream()

.filter(news -> StringUtils.isNotBlank(news.getContent()) && !news.getContent().equals("null"))

.forEach(newsService::saveNews);

logger.info("今日头条新闻内容拉取完成!");

}

}

点击关注,有趣分析

转载于:https://blog.51cto.com/13878196/2394620

Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻相关推荐

  1. 今日头条 爬虫 java_Java爬虫实践:Jsoup+HttpUnit爬取今日头条、网易、搜狐、凤凰新闻...

    0x0 背景 最近学习爬虫,分析了几种主流的爬虫框架,决定使用最原始的两大框架进行练手: Jsoup&HttpUnit 其中jsoup可以获取静态页面,并解析页面标签,最主要的是,可以采用类似 ...

  2. python编程100例头条-python爬虫演示:以爬取今日头条为例

    编者按 众所周知,Python是一门编程语言,操作简洁而清晰.功能专业而强大.入门容易又严谨.2018年,教育部正式将人工智能.物联网.大数据处理划入高中课程,这就意味着,现在的中学生开始就要学习编程 ...

  3. [爬虫笔记01] Ajax爬取今日头条文章

    1.爬取分析 我们首先打开今日头条,搜索"罗志祥" 打开浏览器的开发者工具,红色框中就是我们请求到的数据 将搜索界面的滚动条滑到底,在开发者工具中就可以看到所有请求到的数据,加上前 ...

  4. python获取今日头条搜索信息_python爬虫(十二、爬取今日头条关键词所有文章)

    今日头条 我们以搜索'妹子'为例 那 么 我 们 在 右 上 角 的 搜 索 框 搜 索 妹 子 , 出 来 了 一 系 列 文 章 那么我们在右上角的搜索框搜索妹子,出来了一系列文章那么我们在右上角 ...

  5. java爬取今日头条文章

    闲来无事,写了个爬虫爬取今日头条的文章信息,然后使用ECharts展示出统计结果. 那么怎样爬取今日头条的信息呢? 首先,分析头条页面 文章是通过ajax获取的 所以要找到调用的url,然后跟踪代码查 ...

  6. python爬虫今日头条_python爬虫—分析Ajax请求对json文件爬取今日头条街拍美图

    python爬虫-分析Ajax请求对json文件爬取今日头条街拍美图 前言 本次抓取目标是今日头条的街拍美图,爬取完成之后,将每组图片下载到本地并保存到不同文件夹下.下面通过抓取今日头条街拍美图讲解一 ...

  7. java爬虫的2种爬取方式(HTTP||Socket)简单Demo(一)

    转载自 java爬虫的2种爬取方式(HTTP||Socket)简单Demo(一) 最近在找java的小项目自己写着玩,但是找不到合适的,于是写开始学一点爬虫,自己也是感觉爬虫比较有趣.这里自己找了一个 ...

  8. 利用Ajax爬取今日头条头像,街拍图片。关于崔庆才python爬虫爬取今日头条街拍内容遇到的问题的解决办法。

    我也是初学爬虫,在看到崔庆才大佬的爬虫实战:爬取今日头条街拍美图时,发现有些内容过于陈旧运行程序时已经报错,网页的源代码早已不一样了.以下是我遇到的一些问题. 1.用开发者选项筛选Ajax文件时预览看 ...

  9. Python爬虫:爬取今日头条“街拍”图片(修改版)

    前言 在参考<Python3网络爬虫开发实战>学习爬虫时,练习项目中使用 requests ajax 爬取今日头条的"街拍"图片,发现书上的源代码有些已经不适合现在了, ...

最新文章

  1. LeetCode简单题之按奇偶排序数组
  2. js模仿flash写字动画
  3. 使用ramdisk 优化nagios IO性能
  4. YJX_rxjh_10_2.5.2
  5. 《现代操作系统》第1章读书笔记-- 引论(未完成)
  6. 旅行场景下的个性化营销平台揭秘
  7. Angular 内容投影 content projection 关于选择器问题的单步调试
  8. DNS域传输漏洞利用总结
  9. 证明randomized quicksort的平均running time为nlgn 的数学过程
  10. 微信存储空间占用问题
  11. 安卓第三方接入登陆-新浪登陆
  12. openwrt路由器安装Transmission软件包与web控制台(中文界面)
  13. 按键精灵X学习笔记(二):键盘命令
  14. Vue+Echarts实现饼图统计通过率
  15. 腾讯云数据库SaaS致力于构建数据库分布式云,为更多更广的用户提供服务
  16. Javafx 实现国际象棋游戏
  17. REINFORCE和A2C的异同
  18. 鸿蒙升级包7g,首个华为鸿蒙2.0续航测试来了!实打实10%提升
  19. 防百度云加速html,百度云加速3.0轻松应对全球最大DDoS攻击
  20. linux运行python

热门文章

  1. spss菜单小介绍【跟阿婷一起学spss 03 在入坑边缘疯狂试探】
  2. 相信技术的力量 - RSAC 2020 (2)
  3. Word快速转换幻灯片文稿(转)
  4. python学习记录 day1
  5. Apache源码安装和虚拟主机配置
  6. 我被炒了! 一位36岁程序员的的焦虑与困惑...
  7. Altium Designer快捷键和规则
  8. 失败成就伟大:谷歌的23个失败案例
  9. 神器啊,理工男的春天来了!
  10. c# 指定打开某个路径下的CMD_这招太厉害了,不用鼠标也可以打开指定文件