Android Advanced (XIII) ウェブクローラー&jsonアプリケーション
私が初めてウェブクローラーを扱ったとき、私は素人でした! 何度か悩んだ末に、その原理やそこで使われているjsonの技術を大体理解できたので、同じように戸惑っている人のためにまとめて勉強してみました。
残券12306枚のクエリモジュールを自分のサイトでクロールしてみました。FirefoxのWeb開発者向けコンソールを使うと、以下の図のように、クロールしたWebページのリクエストURLを取得することができます。
The request URL is the URL we need to crawl. In addition, we can learn that the request protocol is Https protocol, using GET way to access. The crawl source code is shown below.
public static String queryDate = "2015-04-19";
public static String from_station = "JNK";
public static String to_station = "BJP";
public static void main(String[] args) throws Exception {
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
System.out.println("Warning: URL Host: " + urlHostName
+ " vs. " + session.getPeerHost());
return true;
}
};
String url = "https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate="
+ queryDate
+ "&from_station="
+ from_station
+ "&to_station="
+ to_station;
ProtocolUrlValidator.trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
String result = WebServiceUtil.invokeByHTTPGET(url, null);
Gson gson = new Gson();
Trains trains = gson.fromJson(result, Trains.class);
List<Items> items = trains.getData().getItems();
if (trains.getHttpstatus() ! = 200) {
trains.getMessages();
} else {
if (items ! = null && items.size() ! = 0)
for (Item item : items) {
System.out.println(item);
}
}
}
}
<span style="font-size:14px;"> Since the protocol used is Https, we need to verify the certificate before accessing it. The blue code block is the URL we need to access, involving the invokeByHTTPGET(url,null) code shown below:</span>
<span style="font-size:18px;">public class WebServiceUtil {
/**
* Calling Web services via SOAP1.1 protocol
*
* @param wsdl WSDL path
* @param method method name
* @param namespace Namespace
* @param headerParameters header parameters
* @param bodyParameters 体参数
* @param isBodyParametersNS whether the body parameters have namespace
* @return String
* @throws Exception
*/
public static String invokeBySoap11(String wsdl, String method,
String namespace, Map<String, String> headerParameters,
Map<String, String> bodyParameters, boolean isBodyParametersNS)
throws Exception {
StringBuffer soapOfResult = null;
// remove ?wsdl, get the list of methods
int length = wsdl.length();
wsdl = wsdl.substring(0, length - 5);
URL url = new URL(wsdl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
OutputStream out = conn.getOutputStream();
// Get the soap1.1 message
StringBuilder sb = new StringBuilder();
sb.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
sb.append("xmlns:ns0=\"" + namespace + "\"");
sb.append(">");
if (headerParameters ! = null) {
sb.append("<soap:Header>");
for (Entry<String, String> headerParameter : headerParameters
.entrySet()) {
sb.append("<ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
sb.append(headerParameter.getValue());
sb.append("</ns0:");
sb.append(headerParameter.getKey());
public static String invokeBySoap12(String wsdl, String method,
String namespace, Map<String, String> headerParameters,
Map<String, String> bodyParameters, boolean isBodyParametersNS)
throws Exception {
StringBuffer soapOfResult = null;
// remove ?wsdl
int length = wsdl.length();
wsdl = wsdl.substring(0, length - 5);
URL url = new URL(wsdl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
OutputStream out = conn.getOutputStream();
// Get the soap1.1 message
StringBuilder sb = new StringBuilder();
sb.append("<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\ " ");
sb.append("xmlns:ns0=\"" + namespace + "\"");
sb.append(">");
if (headerParameters ! = null) {
sb.append("<soap12:Header>");
for (Entry<String, String> headerParameter : headerParameters
.entrySet()) {
sb.append("<ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
sb.append(headerParameter.getValue());
sb.append("</ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
}
sb.append("</soap12:Header>");
}
sb.append("<soap12:Body><ns0:");
sb.append(method);
sb.append(">");
// input parameters
if (bodyParameters ! = null) {
for (Entry<String, String> inputParameter : bodyParameters
.entrySet()) {
if (isBodyParametersNS) {
sb.append("<ns0:");
sb.append(inputParameter.getKey());
sb.append(">");
sb.append(inputParameter.getValue());
sb.append("</ns0:");
sb.append(inputParameter.getKey());
sb.append(">");
} else {
sb.append("<");
sb.append(inputParameter.getKey());
sb.append(">");
sb.append(inputParameter.getValue());
sb.append("</");
sb.append(inputParameter.getKey());
sb.append(">");
}
}
}
sb.append("</ns0:");
sb.append(method);
sb.append("></soap12:Body></soap12:Envelope>");
System.out.println(sb.toString());
out.write(sb.toString().getBytes());
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
soapOfResult = new StringBuffer();
while ((len = is.read(b)) ! = -1) {
String s = new String(b, 0, len, "UTF-8");
soapOfResult.append(s);
}
}
conn.disconnect();
return soapOfResult == null ? null : soapOfResult.toString();
}
/**
* Calling a service via HTTP POST pass-through
*
* @param urlPath
* @param method
* @param namespace
* @param inputParameters
* @return
* @throws Exception
*/
public static String invokeByHTTPPOST(String urlPath, Map<String, String> inputParameters)
throws Exception {
StringBuffer resultStr = null;
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Conte
<span style="font-size:18px;"> At this point, the web crawler process is basically over. The returned results of this experiment are shown below:</span>
<span style="font-size:14px;"> Since the protocol used is Https, we need to verify the certificate before accessing it. The blue code block is the URL we need to access, involving the invokeByHTTPGET(url,null) code shown below:</span>
<span style="font-size:18px;">public class WebServiceUtil {
/**
* Calling Web services via SOAP1.1 protocol
*
* @param wsdl WSDL path
* @param method method name
* @param namespace Namespace
* @param headerParameters header parameters
* @param bodyParameters 体参数
* @param isBodyParametersNS whether the body parameters have namespace
* @return String
* @throws Exception
*/
public static String invokeBySoap11(String wsdl, String method,
String namespace, Map<String, String> headerParameters,
Map<String, String> bodyParameters, boolean isBodyParametersNS)
throws Exception {
StringBuffer soapOfResult = null;
// remove ?wsdl, get the list of methods
int length = wsdl.length();
wsdl = wsdl.substring(0, length - 5);
URL url = new URL(wsdl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
OutputStream out = conn.getOutputStream();
// Get the soap1.1 message
StringBuilder sb = new StringBuilder();
sb.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
sb.append("xmlns:ns0=\"" + namespace + "\"");
sb.append(">");
if (headerParameters ! = null) {
sb.append("<soap:Header>");
for (Entry<String, String> headerParameter : headerParameters
.entrySet()) {
sb.append("<ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
sb.append(headerParameter.getValue());
sb.append("</ns0:");
sb.append(headerParameter.getKey());
public static String invokeBySoap12(String wsdl, String method,
String namespace, Map<String, String> headerParameters,
Map<String, String> bodyParameters, boolean isBodyParametersNS)
throws Exception {
StringBuffer soapOfResult = null;
// remove ?wsdl
int length = wsdl.length();
wsdl = wsdl.substring(0, length - 5);
URL url = new URL(wsdl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
OutputStream out = conn.getOutputStream();
// Get the soap1.1 message
StringBuilder sb = new StringBuilder();
sb.append("<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\ " ");
sb.append("xmlns:ns0=\"" + namespace + "\"");
sb.append(">");
if (headerParameters ! = null) {
sb.append("<soap12:Header>");
for (Entry<String, String> headerParameter : headerParameters
.entrySet()) {
sb.append("<ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
sb.append(headerParameter.getValue());
sb.append("</ns0:");
sb.append(headerParameter.getKey());
sb.append(">");
}
sb.append("</soap12:Header>");
}
sb.append("<soap12:Body><ns0:");
sb.append(method);
sb.append(">");
// input parameters
if (bodyParameters ! = null) {
for (Entry<String, String> inputParameter : bodyParameters
.entrySet()) {
if (isBodyParametersNS) {
sb.append("<ns0:");
sb.append(inputParameter.getKey());
sb.append(">");
sb.append(inputParameter.getValue());
sb.append("</ns0:");
sb.append(inputParameter.getKey());
sb.append(">");
} else {
sb.append("<");
sb.append(inputParameter.getKey());
sb.append(">");
sb.append(inputParameter.getValue());
sb.append("</");
sb.append(inputParameter.getKey());
sb.append(">");
}
}
}
sb.append("</ns0:");
sb.append(method);
sb.append("></soap12:Body></soap12:Envelope>");
System.out.println(sb.toString());
out.write(sb.toString().getBytes());
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
soapOfResult = new StringBuffer();
while ((len = is.read(b)) ! = -1) {
String s = new String(b, 0, len, "UTF-8");
soapOfResult.append(s);
}
}
conn.disconnect();
return soapOfResult == null ? null : soapOfResult.toString();
}
/**
* Calling a service via HTTP POST pass-through
*
* @param urlPath
* @param method
* @param namespace
* @param inputParameters
* @return
* @throws Exception
*/
public static String invokeByHTTPPOST(String urlPath, Map<String, String> inputParameters)
throws Exception {
StringBuffer resultStr = null;
URL url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Conte
上記のコードブロックでは、SOAP1.1 プロトコルで Web サービスを呼び出してリクエストを送信し、SOAP1.2 プロトコルで Web サービスを呼び出して、そして
HTTP POST パススルーと HTTP GET パススルー。具体的なリクエスト方法については、ソースコードのコメント欄で詳しく説明しているので、ここでは繰り返さない。
また、クローリング処理では、jsonオンライン検証ツールで クリックするとリンクが開きます . このツールで行われる主な操作は、json形式の正しさを検証することと、json文字列を基に対応するPOJOクラスを生成することです。これは次の図に示されています。
jsonフォーマット検証
POJOクラスの生成
<span style="font-size:18px;"> At this point, the web crawler process is basically over. The returned results of this experiment are shown below:</span>
注:GSon が単独で json を解析することについて、まだ誤解があるようです。json の文字列の Key は、実際には対応するクラスの変数名に対応します。そうでない場合、パーススタイルでは null になってしまいます
例えば、上記のjson文字列のキーがdataの場合、POJOを作成する際に、変数名を自由に変更できないので、private List<Item>datas; を private List<Item>items; に書き換えると、変数 List<Item> items = 自分で変数名を変更したい場合は、 @SerializedName("datas") private List<Item>items などと注釈するとよいでしょう。
関連
-
ADBサーバーがACKしない問題を解決しました。
-
AndroidStudioのコンパイル時のエラーを解決します。構成 ':classpath' のすべてのアーティファクトを解決できませんでした。
-
Error:Execution failed for task ':app:compileDebugJavaWithJavac' 根本的な解決方法
-
jniとjavaの間でbytearrayを受け渡しする
-
Android携帯で通常のhttpsのサイトにアクセスすると、最初のリクエストで認証パスのトラストアンカーが見つからないと報告され、その後正常にアクセスできるようになり、問題が解決しました。
-
Androidアプリの放送受信機登録(registerReceiver)処理の分析
-
AndroidでデータをExcelファイルに書き出す方法
-
江さんが熟練者から始めさせます。Android Studioは、ランディングページのパスワードスイッチの表示(小さな目)を作成する
-
自作のシンプルなアンドロイド用メモ帳アプリ
-
Androidで色を取得するいくつかの方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ADBサーバーがackしない問題の解決策(ADB接続の問題)
-
[android.os.NetworkOnMainThreadException を解決してください。
-
シンボル 'AppCompatActivity' の解決策を解決できない
-
com.android.ide.common.process.ProcessException が発生する可能性のある原因。aaptの実行に失敗したエラー(解決済み)
-
Intellij Ideaは、シンボルが見つからない、RクラスまたはRパッケージが存在しない、というエラーを報告します。
-
Androidのレイアウトにおけるmarginとpaddingの違いについて
-
Androidの内部育成に磨きをかける2年間
-
Mac OS X用Android Studioショートカット
-
AndroidManifest.xml の use-sdk 警告メソッドを削除する。
-
ARMアセンブリ共通命令 NULL演算 NOP命令