JAVA09-Http协议与爬虫

HTTP 定义了一组请求方法,以表明要对给定资源执行的操作。指示针对给定资源要执行的期望动作,虽然他们也可以是名词, 但这些请求方法有时被称为HTTP动词。每一个请求方法都实现了不同的语义,但一些共同的特征由一组共享:例如一个请求方法可以是 safe, idempotent, 或cacheable (en-US)。

参考资料:https://developer.mozilla.org/zh-CN/docs/Web/HTTP

HTTP常见请求方法

  • HEAD 方法请求一个与GET请求的响应相同的响应,但没有响应体。
  • GET 方法请求一个指定资源的表示形式,使用GET的请求应该只被用于获取数据。
  • POST 方法用于将实体提交到指定的资源,通常用于上传或保存数据。
  • PUT 方法用请求有效载荷替换目标资源的所有当前表示。
  • DELETE 方法用于删除指定的资源。
  • CONNECT 方法建立一个到由目标资源标识的服务器的隧道。
  • OPTIONS 方法用于描述目标资源的通信选项。
  • TRACE 方法沿着到目标资源的路径执行一个消息环回测试。
  • PATCH 方法用于对资源应用部分修改。

HTTP状态码

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status

  • 1xx 信息响应
  • 2xx 成功响应
  • 3xx 重定向
  • 4xx 客户端响应
  • 5xx 服务端响应

HTTP Headers

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

  • Host
  • User-Agent
  • Accept
  • Accept-Language
  • Accept-Encoding
  • Referer
  • Content-Type
  • Location
  • Referer
  • Cookie
  • Set-Cookie

HTTP cookies

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,
它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。
Cookie 使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie 曾一度用于客户端数据的存储,因当时并没有其它合适的存储办法而作为唯一的存储手段,
但现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。
由于服务器指定 Cookie 后,浏览器的每次请求都会携带 Cookie 数据,会带来额外的性能开销。
新的浏览器API已经允许开发者直接将数据存储到本地,
如使用 Web storage API (本地存储和会话存储)或 IndexedDB 。

HttpClient

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

Apache-commons-io

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

Java发送Get请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class Main {
    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpRequest = new HttpGet("https://www.baidu.com");
        try {
            CloseableHttpResponse httpResponse = httpClient.execute(httpRequest);
            StatusLine statusLine = httpResponse.getStatusLine();
            System.out.println(statusLine.getStatusCode() + " " + statusLine.getReasonPhrase());
            HttpEntity httpEntity = httpResponse.getEntity();
            InputStream httpContent = httpEntity.getContent();
            System.out.println(IOUtils.toString(httpContent, StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Jsoup

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.14.3</version>
</dependency>

解析Html结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Main {
    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpRequest = new HttpGet("https://github.com/gradle/gradle/issues");
        try {
            CloseableHttpResponse httpResponse = httpClient.execute(httpRequest);
            StatusLine statusLine = httpResponse.getStatusLine();
            System.out.println(statusLine.getStatusCode() + " " + statusLine.getReasonPhrase());
            HttpEntity httpEntity = httpResponse.getEntity();
            InputStream httpContent = httpEntity.getContent();
            String httpBody = IOUtils.toString(httpContent, StandardCharsets.UTF_8);

            /* 解析html */
            Document document = Jsoup.parse(httpBody);
            Elements issueRow = document.select(".js-issue-row");
            for (Element next : issueRow) {
                System.out.println(next.child(0).child(1).child(0).text());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Crawler pull request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Crawler {
    static class GitHubPullRequest {
        // Pull request的编号
        int number;
        // Pull request的标题
        String title;
        // Pull request的作者的 GitHub 用户名
        String author;

        GitHubPullRequest(int number, String title, String author) {
            this.number = number;
            this.title = title;
            this.author = author;
        }
    }

    // 给定一个仓库名,例如"golang/go",或者"gradle/gradle",返回第一页的Pull request信息
    public static List<GitHubPullRequest> getFirstPageOfPullRequests(String repo) throws IOException {
        List<GitHubPullRequest> list = new ArrayList<>();
        CloseableHttpClient document = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("https://api.github.com/repos/" + repo + "/pulls");
        CloseableHttpResponse httpResponse = document.execute(httpGet);
        InputStream content = httpResponse.getEntity().getContent();
        String body = IOUtils.toString(content, StandardCharsets.UTF_8);
        JSONArray jsonArray = JSON.parseArray(body);
        for (Object object : jsonArray) {
            JSONObject jsonObject = (JSONObject) object;
            list.add(new GitHubPullRequest(
                    jsonObject.getIntValue("number"),
                    jsonObject.getString("title"),
                    jsonObject.getJSONObject("user").getString("login")));
        }
        return list;
    }
}
updatedupdated2025-03-012025-03-01