지난 회에서 Zhihu 크롤러를 만들기 위해 Java를 사용해야 하는 이유에 대해 이야기한 만큼, 이번에는 웹페이지의 콘텐츠를 얻기 위해 코드를 사용하는 방법에 대해 알아보겠습니다.
우선 HTML, CSS, JS, AJAX에 대한 경험이 없다면 W3C(click me, click me)에 가서 조금 배워보는 것을 추천한다.
HTML에 관해 말하자면, 여기에는 GET 액세스 및 POST 액세스 문제가 포함됩니다.
이 측면에 대한 이해가 부족하다면 W3C의 "GET vs. POST" 기사를 읽어보세요.
아하, 여기서는 자세히 설명하지 않겠습니다.
그런 다음 Java를 사용하여 웹 페이지의 콘텐츠를 크롤링해야 합니다.
이때 Baidu가 도움이 될 것입니다.
맞습니다, 그는 더 이상 알려지지 않은 인터넷 속도 테스터가 아닙니다. 그는 곧 우리의 파충류 실험용 피그가 될 것입니다! ~
먼저 Baidu 홈페이지를 살펴보겠습니다.
이와 같은 페이지가 HTML과 CSS의 공동 작업의 결과라는 것은 모두가 알고 있다고 믿습니다.
브라우저에서 페이지를 마우스 오른쪽 버튼으로 클릭하고 "페이지 소스 코드 보기"를 선택합니다.
그렇죠, 이런 것입니다. 바이두 페이지의 소스코드입니다.
다음 작업은 크롤러를 사용하여 동일한 것을 얻는 것입니다.
먼저 간단한 소스코드를 살펴보겠습니다.
import java.io.*;
java.net.* 가져오기;
공개 클래스 메인 {
공개 정적 무효 메인(String[] args) {
// 방문할 링크 정의
문자열 url = "http://www.baidu.com";
//웹 페이지 콘텐츠를 저장할 문자열을 정의합니다.
문자열 결과 = "";
//버퍼링된 문자 입력 스트림 정의
BufferedReader = null;
노력하다 {
//문자열을 URL 객체로 변환
URL realUrl = 새 URL(url);
// 해당 URL에 대한 링크를 초기화합니다.
URLConnection 연결 = realUrl.openConnection();
// 실제 연결 시작
연결.연결();
//URL의 응답을 읽기 위해 BufferedReader 입력 스트림을 초기화합니다.
in = 새로운 BufferedReader(새로운 InputStreamReader(
연결.getInputStream()));
// 캡처된 각 행의 데이터를 임시로 저장하는 데 사용됩니다.
스트링라인;
while ((line = in.readLine()) != null) {
//캡처된 각 행을 순회하여 결과에 저장합니다.
결과 += 줄;
}
} 잡기(예외 e) {
System.out.println("GET 요청을 보내는 중 예외가 발생했습니다!" + e);
e.printStackTrace();
}
// 입력 스트림을 닫으려면 finally를 사용하세요.
마지막으로 {
노력하다 {
if (in != null) {
넣다();
}
} 잡기(예외 e2) {
e2.printStackTrace();
}
}
System.out.println(결과);
}
}
위는 Baidu의 Main 메서드에 액세스하는 Java의 시뮬레이션입니다.
이를 실행하여 결과를 확인할 수 있습니다.
아하, 아까 브라우저에서 본 것과 똑같네요. 이제 가장 간단한 크롤러가 준비되었습니다.
하지만 그렇게 많은 것들이 내가 원하는 것이 전부가 아닐 수도 있습니다. 그 중에서 내가 원하는 것을 어떻게 얻을 수 있습니까?
Baidu의 큰 발 로고를 예로 들어 보겠습니다.
일시적인 필요 사항:
Baidu 로고의 큰 발 사진 링크를 받으세요.
먼저 브라우저 보기 방법에 대해 이야기해 보겠습니다.
이미지를 마우스 오른쪽 버튼으로 클릭하고 요소 검사(Firefox, Google 및 IE11 모두 이 기능이 있지만 이름은 다릅니다)를 선택합니다.
아하, 많은 div로 둘러싸인 불쌍한 img 태그를 볼 수 있습니다.
이 src는 이미지에 대한 링크입니다.
그럼 자바에서는 어떻게 할까요?
코드 시연을 용이하게 하기 위해 모든 코드가 클래스별로 캡슐화되지 않았음을 미리 양해해 주시기 바랍니다.
먼저 이전 코드를 sendGet 함수로 캡슐화해 보겠습니다.
import java.io.*;
java.net.* 가져오기;
공개 클래스 메인 {
정적 문자열 sendGet(문자열 URL) {
//웹 페이지 콘텐츠를 저장할 문자열을 정의합니다.
문자열 결과 = "";
//버퍼링된 문자 입력 스트림 정의
BufferedReader = null;
노력하다 {
//문자열을 URL 객체로 변환
URL realUrl = 새 URL(url);
// 해당 URL에 대한 링크를 초기화합니다.
URLConnection 연결 = realUrl.openConnection();
// 실제 연결 시작
연결.연결();
//URL의 응답을 읽기 위해 BufferedReader 입력 스트림을 초기화합니다.
in = 새로운 BufferedReader(새로운 InputStreamReader(
연결.getInputStream()));
// 캡처된 각 행의 데이터를 임시로 저장하는 데 사용됩니다.
스트링라인;
while ((line = in.readLine()) != null) {
// 캡처된 각 행을 순회하여 결과에 저장합니다.
결과 += 줄;
}
} 잡기(예외 e) {
System.out.println("GET 요청을 보내는 중 예외가 발생했습니다!" + e);
e.printStackTrace();
}
// 입력 스트림을 닫으려면 finally를 사용하세요.
마지막으로 {
노력하다 {
if (in != null) {
넣다();
}
} 잡기(예외 e2) {
e2.printStackTrace();
}
}
결과 반환;
}
공개 정적 무효 메인(String[] args) {
// 방문할 링크 정의
문자열 url = "http://www.baidu.com";
//링크에 액세스하여 페이지 콘텐츠 가져오기
문자열 결과 = sendGet(url);
System.out.println(결과);
}
}
이게 좀 더 깔끔해 보이는데, 제 강박장애를 용서해 주세요.
다음 작업은 얻은 많은 것에서 그림에 대한 링크를 찾는 것입니다.
우리가 생각할 수 있는 첫 번째 방법은 indexof 함수를 사용하여 페이지 소스 코드의 문자열 결과에서 문자열 하위 문자열을 검색하는 것입니다.
예, 이 방법은 직접 indexOf("src")를 사용하여 시작 일련 번호를 찾은 다음 서둘러 종료 일련 번호를 얻는 등 이 문제를 천천히 해결할 수 있습니다.
그러나 우리는 항상 이 방법을 사용할 수는 없습니다. 결국 짚신은 걸어다니는 데만 적합합니다. 나중에 머리를 고정하려면 의족을 잘라야 합니다.
내 방해를 용서하고 계속하십시오.
그렇다면 이 사진의 src를 어떻게 찾을 수 있을까요?
맞습니다, 아래 관객분들 말씀대로 정기매칭입니다.
정규식에 대해 잘 모르는 학생이 있는 경우 [Python] Web Crawler (7): Python의 정규식 자습서를 참조하세요.
간단히 말해서 정규식은 일치와 같습니다.
예를 들어 여기 뚱뚱한 남자 세 명이 빨간색 옷, 파란색 옷, 녹색 옷을 입고 서 있습니다.
규칙은: 녹색으로 된 것을 잡으세요!
그런 다음 그는 뚱뚱한 녹색 남자를 혼자 잡았습니다.
그렇게 간단합니다.
하지만 정규문법은 여전히 방대하고 심오하기 때문에 처음 접할 때 약간 혼란스러울 수밖에 없습니다.
나는 모든 사람에게 정규 온라인 테스트 도구인 정규식 온라인 테스트를 권장합니다.
규칙성을 마법의 무기로 사용하는 경우 Java에서 규칙성을 어떻게 사용합니까?
먼저 간단한 작은 자두를 살펴보겠습니다.
아, 틀렸어, 작은 밤나무.
// 정규식을 사용하여 스타일 템플릿을 정의하고 캡처할 내용은 괄호 안에 있습니다.
// 함정을 묻는 것과 동일하며 일치하면 떨어집니다.
패턴 패턴 = Pattern.compile("href="(.+?)/"");
//매칭을 위한 매처 정의
Matcher matcher = Pattern.matcher("<a href=/"index.html/">내 홈페이지</a>");
// 발견된 경우
if (matcher.find()) {
// 결과를 출력한다
System.out.println(matcher.group(1));
}
실행 결과:
index.html
네, 이것이 우리의 첫 번째 정규 코드입니다.
이 애플리케이션에서 사진을 찍을 수 있는 링크는 여러분의 손끝에 있어야 합니다.
정규 매칭을 함수로 캡슐화한 후 다음과 같이 코드를 수정합니다.
import java.io.*;
java.net.* 가져오기;
import java.util.regex.*;
공개 클래스 메인 {
정적 문자열 SendGet(문자열 URL) {
//웹 페이지 콘텐츠를 저장할 문자열을 정의합니다.
문자열 결과 = "";
//버퍼링된 문자 입력 스트림 정의
BufferedReader = null;
노력하다 {
//문자열을 URL 객체로 변환
URL realUrl = 새 URL(url);
// 해당 URL에 대한 링크를 초기화합니다.
URLConnection 연결 = realUrl.openConnection();
// 실제 연결 시작
연결.연결();
//URL의 응답을 읽기 위해 BufferedReader 입력 스트림을 초기화합니다.
in = 새로운 BufferedReader(새로운 InputStreamReader(
연결.getInputStream()));
// 캡처된 각 행의 데이터를 임시로 저장하는 데 사용됩니다.
스트링라인;
while ((line = in.readLine()) != null) {
// 캡처된 각 행을 순회하여 결과에 저장합니다.
결과 += 줄;
}
} 잡기(예외 e) {
System.out.println("GET 요청을 보내는 중 예외가 발생했습니다!" + e);
e.printStackTrace();
}
// 입력 스트림을 닫으려면 finally를 사용하세요.
마지막으로 {
노력하다 {
if (in != null) {
넣다();
}
} 잡기(예외 e2) {
e2.printStackTrace();
}
}
결과 반환;
}
정적 문자열 RegexString(문자열 targetStr, 문자열 패턴Str) {
// 정규식을 사용하여 스타일 템플릿을 정의하고 캡처할 내용은 괄호 안에 있습니다.
// 함정을 묻는 것과 동일하며 일치하면 떨어집니다.
패턴 패턴 = Pattern.compile(patternStr);
//매칭을 위한 매처 정의
일치자 matcher = Pattern.matcher(targetStr);
// 발견된 경우
if (matcher.find()) {
// 결과를 출력한다
matcher.group(1)을 반환합니다.
}
반품 "";
}
공개 정적 무효 메인(String[] args) {
// 방문할 링크 정의
문자열 url = "http://www.baidu.com";
//링크에 액세스하여 페이지 콘텐츠 가져오기
문자열 결과 = SendGet(url);
// 정규식을 사용하여 이미지의 src 콘텐츠를 일치시킵니다.
String imgSrc = RegexString(result, "다가오는 정규 문법");
// 결과 출력
System.out.println(imgSrc);
}
}
자, 이제 모든 것이 준비되었습니다. 정규 문법만 익히면 됩니다!
그렇다면 어떤 정규 진술이 더 적절합니까?
우리는 src="xxxxxx" 문자열을 잡는 한 전체 src 링크를 잡을 수 있다는 것을 발견했습니다.
따라서 간단한 일반 명령문은 다음과 같습니다: src=/"(.+?)/"
전체 코드는 다음과 같습니다.
import java.io.*;
java.net.* 가져오기;
import java.util.regex.*;
공개 클래스 메인 {
정적 문자열 SendGet(문자열 URL) {
//웹 페이지 콘텐츠를 저장할 문자열을 정의합니다.
문자열 결과 = "";
//버퍼링된 문자 입력 스트림 정의
BufferedReader = null;
노력하다 {
//문자열을 URL 객체로 변환
URL realUrl = 새 URL(url);
// 해당 URL에 대한 링크를 초기화합니다.
URLConnection 연결 = realUrl.openConnection();
// 실제 연결 시작
연결.연결();
//URL의 응답을 읽기 위해 BufferedReader 입력 스트림을 초기화합니다.
in = 새로운 BufferedReader(새로운 InputStreamReader(
연결.getInputStream()));
// 캡처된 각 행의 데이터를 임시로 저장하는 데 사용됩니다.
스트링라인;
while ((line = in.readLine()) != null) {
// 캡처된 각 행을 순회하여 결과에 저장합니다.
결과 += 줄;
}
} 잡기(예외 e) {
System.out.println("GET 요청을 보내는 중 예외가 발생했습니다!" + e);
e.printStackTrace();
}
// 입력 스트림을 닫으려면 finally를 사용하세요.
마지막으로 {
노력하다 {
if (in != null) {
넣다();
}
} 잡기(예외 e2) {
e2.printStackTrace();
}
}
결과 반환;
}
정적 문자열 RegexString(문자열 targetStr, 문자열 패턴Str) {
// 정규식을 사용하여 스타일 템플릿을 정의하고 캡처할 내용은 괄호 안에 있습니다.
// 함정을 묻는 것과 동일하며 일치하면 떨어집니다.
패턴 패턴 = Pattern.compile(patternStr);
//매칭을 위한 매처 정의
일치자 matcher = Pattern.matcher(targetStr);
// 발견된 경우
if (matcher.find()) {
// 결과를 출력한다
matcher.group(1)을 반환합니다.
}
"아무것도"를 반환합니다.
}
공개 정적 무효 메인(String[] args) {
// 방문할 링크 정의
문자열 url = "http://www.baidu.com";
//링크에 액세스하여 페이지 콘텐츠 가져오기
문자열 결과 = SendGet(url);
// 정규식을 사용하여 이미지의 src 콘텐츠를 일치시킵니다.
String imgSrc = RegexString(result, "src="(.+?)/"");
// 결과 출력
System.out.println(imgSrc);
}
}
이러한 방식으로 Java를 사용하여 Baidu 로고에 대한 링크를 가져올 수 있습니다.
글쎄, 나는 Baidu에 대해 많은 시간을 보냈지만 다음에는 공식적으로 Zhihu에 집중하기 시작할 것입니다. ~