一、场景剖析
明天来爬一下我集体的博客,将我的文章题目和地址归纳到一个Excel中,不便查看。
wshanshi能有什么坏心理呢?她只是……想总结下本人文章和相干的地址而已…….
二、界面简略剖析:
开发都懂得,关上调试模式。抉择Elements,而后找到寄存文章的盒子,如下图。
剖析后发现,每个盒子对应寄存一个文章相干的信息。
认真再看,能够发现所有的article标签的class都是同一个。
哎呦,都长一样,这就好整了。通过类选择器联合标签,一下就能拿到了。
点开任意一个文章div,会发现外面外面有文章超链接,题目,形容信息。
联合此次操作的终极目标,得出了以下操作步骤。
场景也剖析完了,就开搞白。
楼主将用两种办法(Python、Java)进行集体文章的数据收集。干就完事……
三、Python实现形式
示例版本:Python 3.8
安装包:requests、beautifulsoup4、pandas
库包装置命令(windows下)
pip install requests pip install beautifulsoup4 pip install pandas
3.1、罕用的库阐明
3.1.1、Requests
什么是Requests?Requests有什么长处、毛病?
中文网地址:https://docs.python-requests.org/zh_CN/latest/user/quickstart.html
3.1.2、Beautiful Soup 4.4.0
阐明: 是一个能够从HTML或XML文件中提取数据的Python库。
中文网地址:https://beautifulsoup.readthedocs.io/zh_CN/latest/
3.1.3、Pandas
阐明:弱小的 Python 数据分析反对库
中文网址:https://www.pypandas.cn/docs/
具体应用详情认准官网happy啊,此处不多做介绍!!!
3.2、代码示例
间接贴代码:获取的文章题目、文章链接进行整合,导出到 .csv文件。
# -*- coding:UTF-8 -*- from bs4 import BeautifulSoup import requests import pandas as pd import openpyxl import re import os def is_in(full_str, sub_str): return full_str.count(sub_str) > 0 def blogOutput(df,url): # if file does not exist write header if not os.path.isfile(url): df.to_csv(url, index = False) else: # else it exists so append without writing the header df.to_csv(url, mode = 'a', index = False, header = False) if __name__ == '__main__': target = 'https://www.gaodaima.com/weixin_43770545' headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47'} res = requests.get(target,headers=headers) #div_bf = BeautifulSoup(res.text) soup = BeautifulSoup(res.text, 'html.parser') #定义输入数组 result=[] for item in soup.find_all("article",{"class":"blog-list-box"}): #提取文章题目 #print(item.find("h4").text.strip()) #提取文章地址链接 #print(item.find("a").get('href')) data = [] data.append(item.find("h4").text.strip()) data.append(item.find("a").get('href')) result.append(data) df = pd.DataFrame(result,columns=['文章题目', '文章地址']) # 调用函数将数据写入表格 blogOutput(df, 'F:/blog_result.csv') print('输入结束')
编码实现后,就跑起来哇。如下图所示,Run(快捷键F5)。
提醒输入结束,可查看导出的文件。
能够的,拿到数据了!!!Python办法就演示这么多(毕竟俺不善于),上面看Java老哥。
四、Java实现形式
Java操作应用Jsoup库,本质操作Dom。
易百教程网址(友情链接):https://www.yiibai.com/jsoup/jsoup-quick-start.html
4.1、环境、库包
Jsoup Maven:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup --> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.2</version> </dependency>
4.2、代码示例
定义BlogVo类
public class BlogVo implements Serializable { /** * 文章题目 */ private String title; /** * 文章地址 */ private String url; @Excel(colName = "文章题目", sort = 1) public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Excel(colName = "文章题目", sort = 2) public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
service接口
/** * 获取提取的博客信息 * * @return */ List<BlogVo> getBlogList(); /** * 导出csv文件 * * @param httpServletResponse * @throws Exception */ void export(HttpServletResponse httpServletResponse) throws Exception;
serviceImpl实现类
@Override public List<BlogVo> getBlogList() { List<BlogVo> list = new ArrayList<>(); try { Document document = Jsoup.connect("https://www.gaodaima.com/weixin_43770545").timeout(20000).get(); Elements e = document.getElementsByClass("blog-list-box"); Elements h4 = e.select(".blog-list-box-top").select("h4"); Elements a = e.select(".blog-list-box").select("a"); List<String> h4List = new ArrayList<>(); List<String> aList = new ArrayList<>(); h4.forEach(item -> { h4List.add(item.text()); }); a.forEach(item -> { String href = item.attr("href"); aList.add(href); }); for (int i = 0; i < h4List.size(); i++) { BlogVo blogVo = new BlogVo(); blogVo.setTitle(h4List.get(i)); blogVo.setUrl(aList.get(i)); list.add(blogVo); } } catch (Exception e) { e.printStackTrace(); } return list; } @Override public void export(HttpServletResponse httpServletResponse) throws Exception { new ExcelExportUtils().export(BlogVo.class, getBlogList(), httpServletResponse, "blog"); }
controller管制层
/** * 导出csv文件 * * @param response * @throws Exception */ @GetMapping("/getExport") public void getExport(HttpServletResponse response) throws Exception { demoService.export(response); }
自定义注解类(Excel )
package com.wshanshi.test.entity; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Excel { public String colName(); //列名 public int sort(); //程序 }
工具类(导出)
package com.wshanshi.test.util; import com.wshanshi.test.entity.Excel; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.formula.functions.T; import javax.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * 导出工具类 */ public class ExcelExportUtils { public void ResponseInit(HttpServletResponse response, String fileName) { response.reset(); //设置content-disposition响应头管制浏览器以下载的模式关上文件 response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".csv"); //让服务器通知浏览器它发送的数据属于excel文件类型 response.setContentType("application/vnd.ms-excel;charset=UTF-8"); response.setHeader("Prama", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); } public void POIOutPutStream(HttpServletResponse response, HSSFWorkbook wb) { try { BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); wb.write(out); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } } @SuppressWarnings({"unchecked", "rawtypes"}) public void export(Class<?> objClass, List<?> dataList, HttpServletResponse response, String fileName) throws Exception { ResponseInit(response, fileName); Class excelClass = Class.forName(objClass.toString().substring(6)); Method[] methods = excelClass.getMethods(); Map<Integer, String> mapCol = new TreeMap<>(); Map<Integer, String> mapMethod = new TreeMap<>(); for (Method method : methods) { Excel excel = method.getAnnotation(Excel.class); if (excel != null) { mapCol.put(excel.sort(), excel.colName()); mapMethod.put(excel.sort(), method.getName()); } } HSSFWorkbook wb = new HSSFWorkbook(); POIBuildBody(POIBuildHead(wb, "sheet1", mapCol), excelClass, mapMethod, (List<T>) dataList); POIOutPutStream(response, wb); } public HSSFSheet POIBuildHead(HSSFWorkbook wb, String sheetName, Map<Integer, String> mapCol) { HSSFSheet sheet01 = wb.createSheet(sheetName); HSSFRow row = sheet01.createRow(0); HSSFCell cell; int i = 0; for (Map.Entry<Integer, String> entry : mapCol.entrySet()) { cell = row.createCell(i++); cell.setCellValue(entry.getValue()); } return sheet01; } public void POIBuildBody(HSSFSheet sheet01, Class<T> excelClass, Map<Integer, String> mapMethod, List<T> dataList) throws Exception { HSSFRow r = null; HSSFCell c = null; if (dataList != null && dataList.size() > 0) { for (int i = 0; i < dataList.size(); i++) { r = sheet01.createRow(i + 1); int j = 0; for (Map.Entry<Integer, String> entry : mapMethod.entrySet()) { c = r.createCell(j++); Object obj = excelClass.getDeclaredMethod(entry.getValue()).invoke(dataList.get(i)); c.setCellValue(obj == null ? "" : obj + ""); } } } } }
PostMan测试导出,成果如下。
哎呦,能够。
数据尽管导出了,然而发现一个问题。数据少了?之前用python取到的数据明明是九十多条。为啥这次只申请到了20多条?有点怪哦。
认真看了下界面,原来是因为页面换为了慢加载。当你滑到最下方的时候请求分页的。
嗷嗷,原来是这样啊。不过,既然看到了接口,那就…..用postMan调下白。
我giao,这径直拿到数据了啊…..
So,还有一种办法。就是间接Http申请这个接口,把分页的条数设置大点就好了。
示例代码如下:
public List<BlogVo> blogHttp() { List<BlogVo> list = new ArrayList<>(); String s = HttpClientUtils.doGetRequest("https://www.gaodaima.com/community/home-api/v1/get-business-list?page=1&size=300&businessType=blog&orderby=&noMore=false&username=weixin_43770545", null, null, null); RespDTO blogDTO = JSON.parseObject(s, RespDTO.class); DataEntity data = blogDTO.getData(); data.getList().forEach(item -> { BlogVo blogVo = new BlogVo(); blogVo.setUrl(item.getUrl()); blogVo.setTitle(item.getTitle()); list.add(blogVo); }); return list; }
成果如下,本人尝试哈。你懂得…….
害,就先这样吧!别学坏哈…..