前回のエピソードでは、Zhihu クローラーを作成するには Java を使用する必要性について説明しました。今回は、コードを使用して Web ページのコンテンツを取得する方法を学習します。
まず、HTML、CSS、JS、AJAX の経験がない場合は、W3C (ここをクリックしてください) にアクセスして少し学ぶことをお勧めします。
HTMLといえば、GETアクセスとPOSTアクセスの問題があります。
この点について理解が足りない場合は、W3C の記事「GET vs. POST」を参照してください。
ああ、ここでは詳しくは説明しません。
次に、Java を使用して Web ページのコンテンツをクロールする必要があります。
このとき、Baidu が役に立ちます。
そう、彼はもはや無名のインターネット速度テスターではなく、私たちの爬虫類モルモットになろうとしているのです! ~
まずは百度のホームページを見てみましょう。
このようなページが HTML と CSS の共同作業の結果であることは誰もが知っていると思います。
ブラウザでページを右クリックし、[ページのソース コードを表示] を選択します。
そうなんです、こんな感じです。これはBaiduページのソースコードです。
次のタスクは、クローラーを使用して同じものを取得することです。
まずは簡単なソースコードを見てみましょう。
java.io.* をインポートします。
java.net.* をインポートします。
パブリッククラス Main {
public static void main(String[] args) {
// アクセスするリンクを定義します
文字列 URL = "http://www.baidu.com";
// Web ページのコンテンツを保存する文字列を定義します
文字列結果 = "";
//バッファリングされた文字入力ストリームを定義する
BufferedReader の = null;
試す {
//文字列をURLオブジェクトに変換
URL realUrl = 新しい URL(url);
// その URL へのリンクを初期化します
URLConnection 接続 = realUrl.openConnection();
// 実際の接続を開始します
接続.connect();
// URL の応答を読み取るために BufferedReader 入力ストリームを初期化します
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// キャプチャされた各行のデータを一時的に保存するために使用されます
文字列行;
while ((line = in.readLine()) != null) {
// キャプチャされた各行を走査し、結果に格納します
結果 += 行;
}
} catch (例外 e) {
System.out.println("GET リクエストの送信中に例外が発生しました!" + e);
e.printStackTrace();
}
// 入力ストリームを閉じるには、finally を使用します。
ついに {
試す {
if (in != null) {
in.close();
}
} キャッチ (例外 e2) {
e2.printStackTrace();
}
}
System.out.println(結果);
}
}
上記は、Baidu の Main メソッドにアクセスする Get の Java のシミュレーションです。
これを実行して結果を確認できます。
ああ、先ほどブラウザで見たものとまったく同じです。この時点で、最も単純なクローラーの準備が整いました。
しかし、そのような膨大な量のものがすべて私が欲しいものであるとは限りません。どうすればその中から欲しいものを手に入れることができるでしょうか?
Baidu の大きな足のロゴを例に挙げてみましょう。
一時的なニーズ:
Baidu ロゴの大きな足の画像リンクを取得します。
まずはブラウザでの視聴方法について説明します。
画像を右クリックし、「要素の検査」を選択します (Firefox、Google、IE11 にはすべてこの機能がありますが、名前は異なります)。
ああ、たくさんの div に囲まれた貧弱な img タグが見えます。
このソースは画像へのリンクです。
では、Java ではどうすればよいでしょうか?
コードのデモンストレーションを容易にするために、すべてのコードがクラスによってカプセル化されているわけではないことをあらかじめご了承ください。
まず、前のコードを sendGet 関数にカプセル化しましょう。
java.io.* をインポートします。
java.net.* をインポートします。
パブリッククラス Main {
静的 String sendGet(String url) {
// Web ページのコンテンツを保存する文字列を定義します
文字列結果 = "";
//バッファリングされた文字入力ストリームを定義する
BufferedReader の = null;
試す {
//文字列をURLオブジェクトに変換
URL realUrl = 新しい URL(url);
// その URL へのリンクを初期化します
URLConnection 接続 = realUrl.openConnection();
// 実際の接続を開始します
接続.connect();
// URL の応答を読み取るために BufferedReader 入力ストリームを初期化します
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// キャプチャされた各行のデータを一時的に保存するために使用されます
文字列行;
while ((line = in.readLine()) != null) {
// キャプチャされた各行を走査し、結果に格納します
結果 += 行;
}
} catch (例外 e) {
System.out.println("GET リクエストの送信中に例外が発生しました!" + e);
e.printStackTrace();
}
// 入力ストリームを閉じるには、finally を使用します。
ついに {
試す {
if (in != null) {
in.close();
}
} キャッチ (例外 e2) {
e2.printStackTrace();
}
}
結果を返します。
}
public static void main(String[] args) {
// アクセスするリンクを定義します
文字列 URL = "http://www.baidu.com";
// リンクにアクセスしてページのコンテンツを取得します
文字列結果 = sendGet(url);
System.out.println(結果);
}
}
これで少しすっきりしましたが、強迫性障害を許してください。
次の課題は、得られたたくさんのものの中から写真へのリンクを見つけることです。
最初に考えられる方法は、indexof 関数を使用して、ページ ソース コードの文字列結果から文字列の部分文字列を検索することです。
はい、このメソッドは、直接、indexOf("src") を実行して開始シリアル番号を検索し、その後急いで終了シリアル番号を取得するなど、この問題をゆっくりと解決できます。
しかし、この方法を常に使用できるわけではありません。結局のところ、草鞋は歩き回るのにのみ適しています。後は、頭を保持するために義足を切断する必要があります。
私の侵入を許して続けてください。
では、この画像のソースはどのように見つけられるのでしょうか?
そうです、下の視聴者が言っているように、通常のマッチングです。
正規表現についてよくわからない学生は、次の記事を参照してください: [Python] Web クローラー (7): Python の正規表現チュートリアル。
簡単に言えば、正規表現はマッチングのようなものです。
たとえば、ここには 3 人の太った男性が立っており、赤い服、青い服、緑の服を着ています。
ルールは「緑色のものを捕まえる」です。
それから彼は太った緑色の男を一人で捕まえました。
それはとても簡単です。
しかし、正則文法は依然として広範囲かつ奥が深いため、初めて触れると少々戸惑うことは避けられません。
私は定期的なオンライン テスト ツールである正規表現オンライン テストを皆さんにお勧めします。
規則性を魔法の武器として、Java で規則性を使用するにはどうすればよいでしょうか?
まずはシンプルな小さな梅を見てみましょう。
ああ、違うよ、小さな栗。
// 正規表現を使用してスタイル テンプレートを定義します。キャプチャされるコンテンツは括弧内にあります
// 罠を埋めるのと同じで、一致すると落ちます。
パターン pattern = Pattern.compile("href=/"(.+?)/"");
// マッチング用のマッチャーを定義する
Matcher matcher = pattern.matcher("<a href=/"index.html/">私のホームページ</a>");
// 見つかった場合
if (matcher.find()) {
// 結果を出力します
System.out.println(matcher.group(1));
}
実行結果:
インデックス.html
はい、これが最初の通常のコードです。
このアプリケーションで写真を取得するためのリンクはすぐに使える必要があります。
通常のマッチングを関数にカプセル化し、コードを次のように変更します。
java.io.* をインポートします。
java.net.* をインポートします。
java.util.regex.* をインポートします。
パブリッククラス Main {
静的 String SendGet(String url) {
// Web ページのコンテンツを保存する文字列を定義します
文字列結果 = "";
//バッファリングされた文字入力ストリームを定義する
BufferedReader の = null;
試す {
//文字列をURLオブジェクトに変換
URL realUrl = 新しい URL(url);
// その URL へのリンクを初期化します
URLConnection 接続 = realUrl.openConnection();
// 実際の接続を開始します
接続.connect();
// URL の応答を読み取るために BufferedReader 入力ストリームを初期化します
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// キャプチャされた各行のデータを一時的に保存するために使用されます
文字列行;
while ((line = in.readLine()) != null) {
// キャプチャされた各行を走査し、結果に格納します
結果 += 行;
}
} catch (例外 e) {
System.out.println("GET リクエストの送信中に例外が発生しました!" + e);
e.printStackTrace();
}
// 入力ストリームを閉じるには、finally を使用します。
ついに {
試す {
if (in != null) {
in.close();
}
} キャッチ (例外 e2) {
e2.printStackTrace();
}
}
結果を返します。
}
静的 String RegexString(String targetStr, String patternStr) {
// 正規表現を使用してスタイル テンプレートを定義します。キャプチャされるコンテンツは括弧内にあります
// 罠を埋めるのと同じで、一致すると落ちます。
パターン pattern = Pattern.compile(patternStr);
// マッチング用のマッチャーを定義する
マッチャー matcher = pattern.matcher(targetStr);
// 見つかった場合
if (matcher.find()) {
// 結果を出力します
matcher.group(1) を返します。
}
戻る "";
}
public static void main(String[] args) {
// アクセスするリンクを定義します
文字列 URL = "http://www.baidu.com";
// リンクにアクセスしてページのコンテンツを取得します
文字列結果 = SendGet(url);
// 正規表現を使用して画像の src コンテンツと一致します
String imgSrc = RegexString(result, "今後の標準文法");
// 結果を出力する
System.out.println(imgSrc);
}
}
さて、これですべての準備が整いました。あとは通常の文法だけです。
それでは、どのような通常のステートメントがより適切なのでしょうか?
文字列 src="xxxxxx" を取得する限り、src リンク全体を取得できることがわかりました。
したがって、単純な通常のステートメント: src=/"(.+?)/"
完全なコードは次のとおりです。
java.io.* をインポートします。
java.net.* をインポートします。
java.util.regex.* をインポートします。
パブリッククラス Main {
静的 String SendGet(String url) {
// Web ページのコンテンツを保存する文字列を定義します
文字列結果 = "";
//バッファリングされた文字入力ストリームを定義する
BufferedReader の = null;
試す {
//文字列をURLオブジェクトに変換
URL realUrl = 新しい URL(url);
// その URL へのリンクを初期化します
URLConnection 接続 = realUrl.openConnection();
// 実際の接続を開始します
接続.connect();
// URL の応答を読み取るために BufferedReader 入力ストリームを初期化します
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// キャプチャされた各行のデータを一時的に保存するために使用されます
文字列行;
while ((line = in.readLine()) != null) {
// キャプチャされた各行を走査し、結果に格納します
結果 += 行;
}
} catch (例外 e) {
System.out.println("GET リクエストの送信中に例外が発生しました!" + e);
e.printStackTrace();
}
// 入力ストリームを閉じるには、finally を使用します。
ついに {
試す {
if (in != null) {
in.close();
}
} キャッチ (例外 e2) {
e2.printStackTrace();
}
}
結果を返します。
}
静的 String RegexString(String targetStr, String patternStr) {
// 正規表現を使用してスタイル テンプレートを定義します。キャプチャされるコンテンツは括弧内にあります
// 罠を埋めるのと同じで、一致すると落ちます。
パターン pattern = Pattern.compile(patternStr);
// マッチング用のマッチャーを定義する
マッチャー matcher = pattern.matcher(targetStr);
// 見つかった場合
if (matcher.find()) {
// 結果を出力します
matcher.group(1) を返します。
}
「何もない」を返します。
}
public static void main(String[] args) {
// アクセスするリンクを定義します
文字列 URL = "http://www.baidu.com";
// リンクにアクセスしてページのコンテンツを取得します
文字列結果 = SendGet(url);
// 正規表現を使用して画像の src コンテンツと一致します
String imgSrc = RegexString(result, "src=/"(.+?)/"");
// 結果を出力する
System.out.println(imgSrc);
}
}
このようにして、Java を使用して Baidu ロゴへのリンクを取得できます。
さて、Baidu について多くの時間を費やしてきましたが、次回からは Zhihu に正式に焦点を当てて、基礎をしっかりと築く必要があります。 ~