文章目录
- 三种抓取方式
- 数据抓取的流程
- 获取文章
- 具体操作
- 获取用户
- 获取图片
- jsoup操作
三种抓取方式
- 直接调用请求接口(最方便,这里使用该方法) HttpClient,OKHttp,RestTemplate,Hutool
- 等网页渲染出明文内容后,从前端页面的内容抓取
- 有些网站可能是动态请求的,不会一次性加载所有的数据,而是要你点击某个按钮,输入某个验证码才会显示出数据 -> 无头浏览器
数据抓取的流程
- 分析数据源(怎么获取)
- 拿到数据后怎么处理
- 写入数据库等存储
获取文章
离线抓取方式
具体操作
- 过滤请求
- 将响应的数据复制到data/passage.json文件中
- 引入Hutool依赖
<!-- https://hutool.cn/docs/index.html#/ -->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>
- 查看官方文档
https://hutool.cn/docs/index.html#/
- 编写测试类
获取用于爬虫的数据
编写测试类
@SpringBootTest
public class CrawlerTest {@Resourceprivate PostService postService;@Testvoid testFetchPassage() {//1.获取数据String json = "{\"current\":1,\"pageSize\":8,\"sortField\":\"createTime\",\"sortOrder\":\"descend\",\"category\":\"文章\",\"tags\":[],\"reviewStatus\":1}";String url = "https://api.code-nav.cn/api/post/search/page/vo";String result = HttpRequest.post(url).body(json).execute().body();//2.处理数据:json转对象Map<String, Object> map = JSONUtil.toBean(result, Map.class);JSONObject data = (JSONObject) map.get("data");JSONArray records = (JSONArray) data.get("records");List<Post> postList = new ArrayList<>();for (Object record : records) {Post post = new Post();JSONObject tempRecord = (JSONObject) record;post.setId(0L);post.setTitle(tempRecord.getStr("title"));post.setContent(tempRecord.getStr("content"));//这里将json数组转为列表再转为json字符串,不知道是为了干什么,为什么不直接把json数组转为json字符串呢?JSONArray tags = (JSONArray) tempRecord.get("tags");List<String> tagList = tags.toList(String.class);// System.out.println(JSONUtil.toJsonStr(tags));post.setTags(JSONUtil.toJsonStr(tagList));System.out.println(JSONUtil.toJsonStr(tagList));post.setUserId(1L);postList.add(post);//3.写入数据库postService.saveBatch(postList);}}
}
- 写入一次性任务
// 取消@Component注释每次项目启动都会执行run任务
//@Component
@Slf4j
public class FetchInitPostList implements CommandLineRunner {@Resourceprivate PostService postService;@Overridepublic void run(String... args) {//1.获取数据String json = "{\"current\":1,\"pageSize\":8,\"sortField\":\"createTime\",\"sortOrder\":\"descend\",\"category\":\"文章\",\"tags\":[],\"reviewStatus\":1}";String url = "https://api.code-nav.cn/api/post/search/page/vo";String result = HttpRequest.post(url).body(json).execute().body();//2.处理数据:json转对象Map<String, Object> map = JSONUtil.toBean(result, Map.class);JSONObject data = (JSONObject) map.get("data");JSONArray records = (JSONArray) data.get("records");List<Post> postList = new ArrayList<>();for (Object record : records) {Post post = new Post();JSONObject tempRecord = (JSONObject) record;post.setId(0L);post.setTitle(tempRecord.getStr("title"));post.setContent(tempRecord.getStr("content"));//这里将json数组转为列表再转为json字符串,不知道是为了干什么,为什么不直接把json数组转为json字符串呢?JSONArray tags = (JSONArray) tempRecord.get("tags");List<String> tagList = tags.toList(String.class);//JSONUtil.toJsonStr(tags);post.setTags(JSONUtil.toJsonStr(tagList));post.setUserId(1L);postList.add(post);//3.写入数据库postService.saveBatch(postList);}}
}
获取用户
每个网站的用户都是自己的,没必要抓取
获取图片
实时抓取:我们自己的网站不存在这些数据,用户要搜的时候,直接从别人的接口(网站)去搜
jsoup库:获取到HTML文档,然后从中解析出需要的字段
jsoup操作
- 导入依赖
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.3</version>
</dependency>
- 打开官网 (https://jsoup.org/),获取示例代码
Document doc = Jsoup.connect("https://en.wikipedia.org/").get();
log(doc.title());
Elements newsHeadlines = doc.select("#mp-itn b a");
for (Element headline : newsHeadlines) {log("%s\n\t%s", headline.attr("title"), headline.absUrl("href"));
}
- 通过在网页前端html界面找对应的css选择器,拿到需要的内容
- 测试代码
//抓取图片@Testvoid testFetchPicture() throws IOException {int current = 1;String url = "https://cn.bing.com/images/search?q=%E5%B0%8F%E9%BB%91%E5%AD%90&form=HDRSC2&first=" + current;Document doc = Jsoup.connect(url).get();Elements elements = doc.select(".iuscp.isv"); //数组,每个元素是每一张图片for (Element element : elements) {//取图片地址murlString m = element.select(".iusc").attr("m");Map<String,Object> map = JSONUtil.toBean(m, Map.class);String murl = (String) map.get("murl");//取标题String title = element.select(".inflnk").attr("aria-label");System.out.println(murl);System.out.println(title);}}