最近迷上了爬虫 在网上找了几个框架 发现用起来都不是特别舒服 在页面筛选元素时 要么只能使用正则 要么就是操作DOM树,还有使用Xpath作为页面元素提取的, 一些其他的设置用起来也不是很顺手因此打算自己编写一个简单的爬虫框架, 方便将来使用
本篇只有页面元素选择的代码
首先分析 我们平时使用爬虫的时候一般爬取的页面内容包括什么
一. 内容
就是正文:开始标签和结束标签中间的文字
二. 标签的属性(图片,视频的URL, 链接)
img 的src 的值
视频的src的值
a标签的href属性
其次就是定位了
定位主要通过标签进行定位, 而标签主要分为三类 单标签 (img, link等), 嵌套标签(div 和span) ,双标签
针对不同标签需设置不同的字符串截取规则
以下是我自定义的一套标签筛选规则可以通过自定义的字符串截取指定的内容主要
通过使用自定义的截取字符串 进行页面元素的筛选
格式为
标签>定位
标签>属性>定位
测试使用
打开csdn
截取所有的a标签的href属性
试个复杂的
查看页面代码
页面筛选代码如下:
package com.tpddy.spider.utils;
import cn.hutool.core.util.StrUtil;
import lombok.Getter;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author GEP
* @DESCRIPTION 文本区分器
* @create 2019/8/14 0014
*/
public class HtmlTextDistinct {
private static final String[] divs = {
"div", "span"};
private static final String[] one = {
"link", "br", "hr", "img", "input", "param", "meta", "link"};
private static final List<String> oneTitle = new ArrayList<>();
private static final List<String> nesteTitle = new ArrayList<>();
static {
oneTitle.addAll(Arrays.asList(one));
nesteTitle.addAll(Arrays.asList(divs));
}
private static String getSimple(String source) {
return source
// 去除空格
.replaceAll(" +", "")
// 去除特殊符号
.replaceAll("\r+", "")
.replaceAll("\t+", "")
.replaceAll("\n+", "")
// 去除注释
.replaceAll("<!--(.*?)-->+", "");
}
/**
* 获取标签的所有内容
* 从标签的起始位置到标签的结束位置
*
* @param source
* @param tag
* @return
*/
public static List<String> getDataByTag(String source, String tag) {
source = getSimple(source);
// 单标签返回结束
if (isTag(tag, oneTitle)) {
return getOneTagData(source, tag);
// 嵌套标签
} else if (isTag(tag, nesteTitle)) {
return getNesteTagData(source, tag);
// 普通标签
} else {
return getSimpleTagData(source, tag);
}
}
/**
* 获取数据
* @param source
* @param tag
* @return
*/
public List<String> getHtmlData(String source, String tag){
return getData(getSimple(source), tag);
}
/**
* 获取数据
*
* @param source
* @param reTag
* @return
*/
public List<String> getData(String source, String reTag) {
Tag tag = new Tag(reTag);
String nextElement = tag.getNextElement();
String[] elemetntTags = nextElement.split(">");
if (elemetntTags.length == 2) {
List<String> dataByTag = getDataByTag(source, elemetntTags[0]);
List<String> dataByFilter = getDataByFilter(dataByTag, elemetntTags[1]);
if (tag.hasNextElement()) {
List<String> result = new ArrayList<>();
for (String s : dataByFilter) {
result.addAll(getData(s, tag.getSource()));
}
return result;
} else {
return dataByFilter.stream().map(HtmlTextDistinct::getDataRemoveTag).collect(Collectors.toList());
}
} else if (elemetntTags.length == 3) {
List<String> dataByTag = getDataByTag(source, elemetntTags[0]);
List<String> prop = dataByTag.stream().map(data -> getDataByProp(data, elemetntTags[1])).filter(StrUtil::isNotBlank).collect(Collectors.toList());
return getDataByFilter(prop, elemetntTags[2]);
} else {
return getDataByTag(source, reTag).stream().map(HtmlTextDistinct::getDataRemoveTag).collect(Collectors.toList());
}
}
/**
* 根据定位标签进行筛选
*
* @param list
* @param filterStr
* @return
*/
public static List<String> getDataByFilter(List<String> list, String filterStr) {
List<String> result = new ArrayList();
// * 标识全部截取
if ("*".equals(filterStr)) {
return list;
}
Set<Integer> indexSet = new HashSet<>(