目录
2. 找到你getElementById定位到你想要抓取的地方。
各位小伙伴好!最近研究了一下用jsoup来抓取网页。也是小有心得。记录一下怕自己以后忘了。
首先先我们要先明白jsoup是什么,这边简单介绍一下。(详细请移步官网学习:http://jsoup.org/)
官方网站是这样说的:jsoup是一个用于处理现实世界HTML的Java库。它提供了一个非常方便的API,用于获取URL以及提取和操作数据,使用最好的HTML5 DOM方法和CSS选择器。
说白了就是一款 Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
具体看怎么用的。
一、导入依赖
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
题外:
我们的需求是抓取网页。抓取网页的标题、文章内容、图片、链接。
请不要违法犯罪。
二、实现。
1.写一个工具类,类里面封装方法。传入url地址。
public class JsoupUtils {public List<CrawlContent> parseCj(String url) throws Exception { //String url = "http://xxxx"; LinkedHashMap<String, CrawlContent> contentMap = new LinkedHashMap<>(); // 使用LinkedHashMap保持插入顺序 //根据url地址获取document网页内容。可以打印一下document.html();并且设置超时时间 Document document = Jsoup.parse(new URL(url), 30000);}
}
2. 找到你getElementById定位到你想要抓取的地方。
可以通过找到你要抓取的网页——鼠标右键——检查,找到对应的容器。
public class JsoupUtils {
public List<CrawlContent> parseCj(String url) throws Exception {
//String url = "http://xxx";
LinkedHashMap<String, CrawlContent> contentMap = new LinkedHashMap<>(); // 使用LinkedHashMap保持插入顺序
//根据url地址获取document网页内容。可以打印一下document.html();并且设置超时时间
Document document = Jsoup.parse(new URL(url), 30000);
//定位
Element listData = document.getElementById("listData");
Elements elements = listData.getElementsByTag("div");
for (Element el : elements) {
//获取标题
String span = el.getElementsByTag("span").eq(0).text();
//获取链接
String attr = el.getElementsByTag("a").eq(0).attr("href");
//链接不是已http开头就拼接
if (!attr.startsWith("http")) {
attr = ("http://www.scsjzyxh.cn" + attr);
}
//检查标题或链接是否已存在
if (contentMap.containsKey(span) || contentMap.containsKey(attr)) {
continue; // 跳过重复数据
}
//打印标题
System.out.println(span);
//打印链接
System.out.println(attr);
//创建CrawlContent对象
CrawlContent crawlContent = new CrawlContent();
crawlContent.setTitle(span);
crawlContent.setConnect(attr);
}
}
其实你可以打印你一下找到没有。
三、获取链接里面的文章内容。
思路是刚才document循环里面循环传入链接,并且根据链接定位具体你想获取的内容。
public class JsoupUtils {
public List<CrawlContent> parseCj(String url) throws Exception {
//String url = "http://xxx";
LinkedHashMap<String, CrawlContent> contentMap = new LinkedHashMap<>(); // 使用LinkedHashMap保持插入顺序
//根据url地址获取document网页内容。可以打印一下document.html();并且设置超时时间
Document document = Jsoup.parse(new URL(url), 30000);
//定位
Element listData = document.getElementById("listData");
Elements elements = listData.getElementsByTag("div");
for (Element el : elements) {
//获取标题
String span = el.getElementsByTag("span").eq(0).text();
//获取链接
String attr = el.getElementsByTag("a").eq(0).attr("href");
//链接不是已http开头就拼接
if (!attr.startsWith("http")) {
attr = ("http://www.scsjzyxh.cn" + attr);
}
//检查标题或链接是否已存在
if (contentMap.containsKey(span) || contentMap.containsKey(attr)) {
continue; // 跳过重复数据
}
//打印标题
System.out.println(span);
//打印链接
System.out.println(attr);
//创建CrawlContent对象
CrawlContent crawlContent = new CrawlContent();
crawlContent.setTitle(span);
crawlContent.setConnect(attr);
//放防止有404链接
try {
//传入刚才获取的文章链接
Document contentDocument = Jsoup.parse(new URL(attr), 30000);
// 提取clearfix文章来源内容
StringBuilder contentBuilder = new StringBuilder();
//根据select选择器找到clearfix容器列表的p标签
Elements contentElements1 = contentDocument.select(".clearfix p");
for (Element contentElement : contentElements1) {
//可以打印一下看拿到了没有
System.out.println(contentElement.html());
//去重。去多余空格,去多余分隔符。
contentBuilder.append(contentElement.text().trim()).append("\n");
}
crawlContent.setTextContent(contentBuilder.toString());
} catch (IOException e) {
System.out.println("获取链接内容时发生错误:" + attr);
// 在这里可以进行适当的异常处理,比如记录日志或跳过该链接的处理
continue; // 跳过当前循环迭代,继续处理下一个链接
}
}
}
四、去重
为了保证我们的数据一致性
我们需要用set去重。
public class JsoupUtils {
public List<CrawlContent> parseCj(String url) throws Exception {
//String url = "http://xxx";
LinkedHashMap<String, CrawlContent> contentMap = new LinkedHashMap<>(); // 使用LinkedHashMap保持插入顺序
//根据url地址获取document网页内容。可以打印一下document.html();并且设置超时时间
Document document = Jsoup.parse(new URL(url), 30000);
//定位
Element listData = document.getElementById("listData");
Elements elements = listData.getElementsByTag("div");
for (Element el : elements) {
//获取标题
String span = el.getElementsByTag("span").eq(0).text();
//获取链接
String attr = el.getElementsByTag("a").eq(0).attr("href");
//链接不是已http开头就拼接
if (!attr.startsWith("http")) {
attr = ("http://www.scsjzyxh.cn" + attr);
}
//检查标题或链接是否已存在
if (contentMap.containsKey(span) || contentMap.containsKey(attr)) {
continue; // 跳过重复数据
}
//打印标题
System.out.println(span);
//打印链接
System.out.println(attr);
//创建CrawlContent对象
CrawlContent crawlContent = new CrawlContent();
crawlContent.setTitle(span);
crawlContent.setConnect(attr);
//放防止有404链接
try {
//传入刚才获取的文章链接
Document contentDocument = Jsoup.parse(new URL(attr), 30000);
// 提取clearfix文章来源内容
StringBuilder contentBuilder = new StringBuilder();
//根据select选择器找到clearfix容器列表的p标签
Elements contentElements1 = contentDocument.select(".clearfix p");
for (Element contentElement : contentElements1) {
//可以打印一下看拿到了没有
System.out.println(contentElement.html());
//去重。去多余空格,去多余分隔符。
contentBuilder.append(contentElement.text().trim()).append("\n");
}
crawlContent.setTextContent(contentBuilder.toString());
} catch (IOException e) {
System.out.println("获取链接内容时发生错误:" + attr);
// 在这里可以进行适当的异常处理,比如记录日志或跳过该链接的处理
continue; // 跳过当前循环迭代,继续处理下一个链接
}
removeDuplicates(contentArrayList); // Remove duplicates from the list
return contentArrayList;
}
/**
* 去重
* @param contentList
*/
private void removeDuplicates(List<CrawlContent> contentList) {
Set<String> uniqueKeys = new HashSet<>();
List<CrawlContent> uniqueContentList = new ArrayList<>();
for (CrawlContent content : contentList) {
String key = content.getTitle() + content.getConnect();
if (!uniqueKeys.contains(key)) {
uniqueKeys.add(key);
uniqueContentList.add(content);
}
}
contentList.clear();
contentList.addAll(uniqueContentList);
}
}
这样我们的工具类就写完了。
五、保存在数据库
可以写一个测试类也可以业务层调用
传入url地址。
使用批量添加方法添加。
@SpringBootTest(classes = JsoupdemoApplication.class)
@RunWith(SpringRunner.class)
public class CrawlContentTest {
@Autowired
private CrawlContentMapper contentMapper;
@Test
public void Test() throws Exception{
List<CrawlContent> crawlContents = new JsoupUtils().parseCj("http://xxx");
contentMapper.insertBatch(crawlContents);
}
}
效果:
六、总结
jsoup里面有很多document里面有很多api
跟前端js里面的document一样。还是比较容易入门的。