ホームページ > 記事 > ウェブフロントエンド > V2EX フォーラム クライアント投稿情報のクローリング (1)_html/css_WEB-ITnose
私は V2EX に頻繁にアクセスするので、空き時間を利用して Android クライアントを作成することにしました。オープンソースはここ https://github.com/ihgoo です。 /V2EX
仕事をうまくやり遂げたい場合は、まずツールを強化する必要があります。プロジェクト全体は Gradle で構築され、Android Studio によって開発されます。
会社のプロジェクトも Android Studio に移行しました。Studio には、変数を入力するときに、最初に変数のスペルを覚えていない場合に特に気に入っている機能があります。後で自動的にプロンプトが表示されます。プラグインも多数あり、ビジネスロジックのみに重点を置いて開発がより確実なものになってきています。
フォーラムクライアントはビジネスロジックに応じて以下のモジュールに分割
非言語での閲覧モジュール・ログイン状態
ユーザーモジュール
ログイン状態モジュール
依存関係ライブラリはネイティブ コントロールと成熟したフレームワークの使用を検討します
compile 'com.jakewharton:butterknife:6.1.0' compile 'com.squareup.retrofit:retrofit:1.9.0'compile 'com.squareup:otto:+'compile 'com.facebook.fresco:fresco:0.1.0+'compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'compile 'com.squareup.okhttp:okhttp:2.0.0'
butterknife: jack master によって書かれた Ioc フレームワーク。dagger に相当します。idea/studio にはバターナイフをサポートするプラグインがあり、ワンクリックで findviewbyid を見つけられます。
レトロフィット: 強力なネットワーク リクエスト ライブラリ。
fresco: 画像ライブラリをロードします。これを使用する前は、常に Imageloader を使用していました。プロジェクト内で画像の gif とプログレッシブ表示をサポートする必要があるため、これを使用します。
オットー:eventBus フレームワーク!アーティファクトを切り離すことで、すべてがよりシンプルになります。
パッケージ構造は次のとおりです:
app: アプリのアプリケーションについて、など。
client: ネットワークリクエストヘッダーの定義、ネットワークリクエストライブラリの設定など。
core: 基本フレームワーク、mvc 構造の c に相当します。 もちろん、ここでの c は、Controller
model: モデル層
paser: 解析層を指します。 json であっても html であっても、エンティティ クラスはこの分析層によって生成されます。
永続性: 定数クラス、データベース フィールド、インターネット リクエスト フィールド、アプリ構成フィールドなどを配置します。
ui: プレゼンテーション層を表示します。
utils: いくつかの便利なツール クラス
プロジェクトは Gradle でビルドされ、アプリはモジュールとして使用され、他のモジュールはマウントとしてアプリにマウントされます。他のモジュールをすぐに置き換えることができ、ソース コードを変更できること (aar 形式でインポートされたソース コードは変更できません)。
公式json APIの呼び出し回数に制限があるため、htmlページの解析を検討しました。
コンピュータ側の HTML が大きすぎるため、電力を節約し、アプリが占有するリソースを削減するために、WAP 側のページをモバイルとして偽装できます。ここでは、HTML を解析するために
を使用します。これは、Python の pyquery に相当し、サポートされています。必要なリソースを取得するための Jqery のようなセレクター メソッド。シンプルで便利ですが、非常に粗雑です。唯一の欠点は、ページ内の一部の要素が ajax 形式で形成されている場合、httpunit を使用できますが、Web ページを実行するためにブラウザー カーネルを起動する必要があるため、混乱が生じることです。 Web ページの作成が完了したら、情報を取得します。
public class ApiHeaders implements RequestInterceptor { private String sessionId; public void setSessionId(String sessionId) { this.sessionId = sessionId; } public void clearSessionId() { sessionId = null; } @Override public void intercept(RequestFacade request) { request.addHeader("User-Agent", "Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19"); request.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"); if (sessionId != null) { } }}
投稿リストを解析します
アバター 著者 アバター
public class PaserFourmList { public static ArrayList<ForumItemBean> paser2ForumItem(String string) { Document document = Jsoup.parse(string); Elements elements = document.select(".cell").select(".item"); ArrayList<ForumItemBean> list = new ArrayList<>(); for (Element element : elements) { // avatar // node // title // small fade (time) // small fade author // count_livid String avatar = element.select(".avatar").first().attr("src"); String node = element.select(".node").first().html(); String username = element.select(".small > strong").first().text(); String countLivid = element.getElementsByClass("count_livid").text(); String time = element.select(".small").select(".fade").get(1).text(); String href = element.getElementsByClass("item_title").html(); if (href.length()!=0){ href = href.substring(12, href.indexOf("#")); } int indexOf = time.indexOf("前"); if (indexOf != -1) { time = time.substring(0, indexOf); } ForumItemBean forumItemBean = new ForumItemBean(); Member member = new Member(); member.setAvatarMini(avatar); member.setUsername(username); forumItemBean.setId(Misc.parseInt(href, 0)); forumItemBean.setMember(member); forumItemBean.setLastTime(time); forumItemBean.setReplies(Misc.parseInt(countLivid, 0)); forumItemBean.setTitle(element.select(".item_title").first().select("[href]").html()); list.add(forumItemBean); } return list; }}
#d1dea21e92cc4b986367cc32d8e4278f もあります。このようなものは element.select(".content-type") を使用して解析できません。 getElementsByClass(( "コンテンツ タイプ").