Java-网页爬虫

本文介绍了使用Java和Maven创建爬虫项目的全过程,包括Idea的基本设置、Maven的配置与添加、爬虫框架WebMagic的使用以及调试和数据处理方法。详细讲解了如何解决配置过程中的SLF4J报错、Http请求实现、字符串与数组转换等问题,提供了单元测试和单步调试的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

logo

完整文章地址

idea基本设置

File>Setting打开idea基本设置,可以更改字体主题,安装插件等

建议安装中文翻译插件和Codota插件

image-20210507095023736

idea创建项目

1.参考文章

IDEA新建一般Java项目

语言版本和环境版本不一致导致错误:Error:java: 无效的源发行版

2.注意事项
(1)配置

新建一般Java项目时,一般选择默认配置进行

(2)打开项目

打开的项目文件时,文件结构如下,文件路径多出一层或少一层文件,idea都不能识别出该项目(程序文件都要放到src文件中):

image-20210507092554533

(3)配置修改

项目结构(文件 > 项目结构)中可以修改项目的一些配置(可设置项目,模块的语言级别)

image-20210507095156216

(4)标记目录

标记目录可以自定义源根目录等,一般不改动,默认src为源根目录

(5)添加Maven框架

在Java一般项目中没有meavn的选项,可以在后期加上Maven框架支持

image-20210507101055813

添加了Maven框架后,还需要重新加载Maven项目即可完成框架添加

image-20210507101357206

配置meavn

1.参考文章

Meavn配置过程

依赖添加错误

手动添加jar包

2.注意事项
(1)maven配置

idea有自己自带的maven,如果想自定义到自己下载的maven文件,可以在设置中修改(这样的修改只是针对该项目,新建的项目还是使用默认的maven)

image-20210507100212095

  • 设置主目录
  • 用户设置文件指向maven的setting文件
  • 可以新建一个文件用于存储本地库
(2)Meavn创建项目

除了在一般项目创建后再添加Maven框架,我们也可以直接使用Meavn框架创建项目

image-20210507101919573

区别于一般的Java项目,使用Meavn框架创建的会在src新建两个文件夹:main(放主程序)和test(放测试程序)

(3)meavn添加包
  • 通过pom.xml添加依赖

在pom.xml文件中添加<dependency></dependency>标签,如下

<dependency>
    <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.6.1</version>
 </dependency>

要注意要是在<dependencies></dependencies>内添加依赖

我们可以通过Maven Repositor查找对应包的依赖项xml文本

最后加载Maven包变更完成依赖项的添加

image-20210507103208170

  • 手动添加jar包

meavn找不到相关包时,可以直接下载jar文件到本地包,放在刚刚设置Maven本地库存储文件中,然后使用maven导入

爬虫配置

1.参考文章

WebMagic 文档

出现log4j警告解决方法

出现了SLF4J的报错解决方法:添加依赖即解决

文档中爬虫基本使用介绍

2.注意事项
(1)爬虫框架添加

爬虫框架采用了易于上手的WebMagic框架,在pom.xml文件中添加相关依赖

<dependency>
	<groupId>us.codecraft</groupId>
	<artifactId>webmagic-core</artifactId>
    <version>0.7.4</version>
</dependency>
<dependency>
     <groupId>us.codecraft</groupId>
     <artifactId>webmagic-extension</artifactId>
     <version>0.7.4</version>
</dependency>
(2)无法爬取网页

无法爬取TLS1.2协议站点的问题

在依赖中把WebMagica改成最新版本(0.7.4以上)即可解决

(3)SLF4J报错

出现了SLF4J报错可以添加以下依赖

<dependency>
	<groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
 	<version>1.7.2</version>
</dependency>
(4)爬取方法
  • 实现实现PageProcessor接口,设置爬虫相关配置
private Site site = Site.me()
        .setCharset("UTF-8")
        .setRetryTimes(3)
        .setSleepTime(100);
  • process编写抽取逻辑,可以定义爬取页面的规则
public void process(Page page){

 	// 爬取title放入父类私有属性中
    List title = page.getHtml()
        .css("li > div > div.details > span.link.h-cite.u-repost-of > a")
        .regex(">(.+)</a>",1)
        .all();
        
    	set_title(title);
        
}
  • Spider类执行爬虫
Spider.create(obj)
      .addUrl(url)
      //开启4个线程抓取
      .thread(4)
      //启动爬虫
      .run();
(5)正则匹配问题

WebMagic链式抽取元素中使用的正则是不区分大小写的

调试方法

1.参考文章

IDEA单元测试设置过程

深入学习 Intellij IDEA 调试技巧

2.单元测试
(1)单元测试理解

单元测试实质上是在主运行程序之外,为某个方法创建单独的测试程序,而不必只有一个执行入口进入程序

(2)单元测试特殊情况

抽象方法在单元测试时不能被调用,因为抽象类不能有实例不能直接调用

(3)单元测试使用案例
// 爬取工具类测试
    @Test
    void spider() {
        new Tool().spider(new Lobsters() ,"https://lobste.rs/");

   }
(4)单元测试生成

idea可以快捷为类生成一个测试类,并可以勾选生成测试方法

image-20210508081411414

3.单步调试
(1)断点设置

设置断点可以让程序在调试时从入口开始执行到断点所在代码

image-20210508083551638

不设断点调试,程序会执行完全部代码,无法实现单步调试

(2)调试显示

image-20210508084409131

  • 重新调试:当单步调试进入加载类等奇怪的地方时,可以重新调试,直到断点出现勾号,说明调试成功
  • 调试过程中,步过(Setp Over)使用频率最高,当碰到方法时,不会进入方法内,而是直接调用方法,然后进入下一行
  • 步进( Step Into)则会进入方法内

构造子类

1.参考文章

java中父类与子类有相同属性调谁?取决于左边

父类私有属性和私有方法的继承

Java this 关键字用法

2.注意事项
(1)子类属性继承问题
  • 子类是继承了父类的私有属性和私有方法,只是子类没有权限直接访问父类的私有属性和私有方法。但是我们可以通过继承父类get和set方法访问到父类的私有属性

    // 修改私有属性方法
    public void set_title(List title){
        this.title = title;
     }
    
    // 访问私有属性方法
    public List show_title(){
         return this.title;
        }
    
  • 父类属性不可被重写,只会被调用,父类方法可以被重写,也可以被调用

  • 当子类中存在和父类同名属性,父类属性会隐藏起来,在多态的情况下属性被调用时会激活父类属性子类属性隐藏起来,而方法不会隐藏,一旦被重写,只能使用super来在子类调用

(2)继承中this指向问题
  • 对于方法的覆盖,new的谁就调谁,这就是多态。
  • 对于成员变量的覆盖,this在哪个类就指向哪个类的成员变量,没有多态。
  • 无论子类是否覆盖成员变量,this始终访问父类的成员变量
  • 静态方法中,无法使用this引用上下文内容(属性,方法)
(3)抽象方法使用问题
  • 抽象类是作为一个模板存在的,不能创建抽象类对象,需要用子类实现所有其抽象方法后变为非抽象类才能间接实例化
  • 抽象方法只有声明没有实现(对于不知道该怎么实现的方法,我们可以声明为抽象方法),强制子类必须重写抽象方法

Http请求

1.参考文章

Java实现md5加密

Java内部类实现http请求

http请求与多线程

URL中关于空格的编码

2.注意事项
(1)Http请求实现
  • get请求

    String urlNameString = url + '?' + param;
    URL realUrl = new URL(urlNameString);
    // 打开链接,强转换为httpURLConnection类
    URLConnection connection = realUrl.openConnection();
    
    // 设置通用请求属性
    connection.setRequestProperty("accept", "*/*");
    connection.setRequestProperty("connection", "Keep-Alive");
    connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
    // 建立实际链接
    connection.connect();
    
    
    // 请求成功获得输入流
    BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    
    // 获得返回结果
    String res = in.readLine();
    
  • post请求

    URL realUrl = new URL(url);
    // 打开和URL之间的连接
    URLConnection conn = realUrl.openConnection();
    
    // 设置通用的请求属性
    conn.setRequestProperty("accept", "*/*");
    conn.setRequestProperty("connection", "Keep-Alive");
    conn.setRequestProperty("user-agent",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
    
    // 发送POST请求必须设置如下两行
    conn.setDoOutput(true);
    conn.setDoInput(true);
    
    // 获取URLConnection对象对应的输出流
    out = new PrintWriter(conn.getOutputStream());
    // 发送请求参数
    out.print(param);
    // flush输出流的缓冲
    out.flush();
    
    // 定义BufferedReader输入流来读取URL的响应
    in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    
    //获得返回结果 
    String res = in.readLine();
    
  • Java发起http请求后,返回值为String类型

  • 注意请求api的QPS(每秒请求量),我们可以通过Thread.currentThread().sleep(1000);//毫秒 简单实现延时

  • 链接编码问题,有时候链接请求失败是因为空格没有编码为%20,而导致请求失败

(2)Java加密问题

​ 实现md5加密

// md5加密工具
public String getMd5(String input)
{
    try {

        // 使用哈希MD5调用静态getInstance方法
        MessageDigest md = MessageDigest.getInstance("MD5");

        // digest() 方法调用来计算消息摘要
        //  of an input digest() return array of byte
        byte[] messageDigest = md.digest(input.getBytes());

        // 将字节数组转换为符号表示
        BigInteger no = new BigInteger(1, messageDigest);

        // 将消息摘要转换为十六进制值
        String hashtext = no.toString(16);
        while (hashtext.length() < 32) {
            hashtext = "0" + hashtext;
        }
        return hashtext;
    }

    // 用于指定错误的消息摘要算法
    catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}
Java数据处理
1.参考文章

Java数组遍历方法

java遍历List方法

List和Array相互转换

2.注意事项
(1)字符串与数组转换
  • 字符串转换成数组

    String.split() 方法,Java 中通常用 split() 分割字符串,返回的是一个数组

    String str = "123abc";
    String[] arr = str.split("");
    for (int i = 0; i < arr.length; i++) { // String数组
        System.out.print(arr[i]); // 输出 1 2 3 a b c
    }
    
  • 数组转换为字符串

    String[] arr = { "123", "abc" };
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < arr.length; i++) {
        sb.append(arr[i]); // String并不拥有append方法,所以借助 StringBuffer
    }
    String sb1 = sb.toString();
    System.out.println(sb1); // 输出123abc
    
(2)数组遍历方法
  • 传统for循环方法

  • for each循环(foreach只能用于普通数组)

  • 利用Array类中的toString方法(不能直接打印数组,System.out.println(array)这样打印是的是数组的首地址)

    int[] array = {1,2,3,4,5};
    System.out.println(Arrays.toString(array))
    
(3)List遍历方法
  • 迭代器遍历(hasNext和next方法)
  • for each遍历(从List中获得的元素是对象)
  • 传统for循环遍历(使用size方法获得List长度)
  • Lambda表达式
(3)Java中的正则表达式
  • 注意该正则方法,一定是先find后group,group()方法通过前一个成功的find()方法调用返回找到的字符串
(5)List与Array的转换
  • List to Array

    使用List 提供的toArray的接口对List进行转换

    // 指定类型转换
    String[] array=list.toArray(new String[list.size()]);
    
  • Array to List

    使用ArrayList的构造方法进行转换

    List<String> list = new ArrayList<String>(Arrays.asList(array));
    

,5};
System.out.println(Arrays.toString(array))




##### (3)List遍历方法

- 迭代器遍历(hasNext和next方法)
- for each遍历(从List中获得的元素是对象)
- 传统for循环遍历(使用size方法获得List长度)
- Lambda表达式



##### (3)Java中的正则表达式

- 注意该正则方法,一定是先find后group,group()方法通过前一个成功的find()方法调用返回找到的字符串



##### (5)List与Array的转换

- List to Array

使用List 提供的toArray的接口对List进行转换

```Java
// 指定类型转换
String[] array=list.toArray(new String[list.size()]);
  • Array to List

    使用ArrayList的构造方法进行转换

    List<String> list = new ArrayList<String>(Arrays.asList(array));
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值