关于python:PythonJava爬取个人博客信息导出到Excel

37次阅读

共计 7624 个字符,预计需要花费 20 分钟才能阅读完成。

一、场景剖析

明天来爬一下我集体的博客,将我的文章题目和地址归纳到一个 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://blog.csdn.net/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://blog.csdn.net/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://blog.csdn.net/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;
}

成果如下,本人尝试哈。你懂得 …….

害,就先这样吧!别学坏哈 …..

正文完
 0