最近、WeChat公式アカウントの記事情報をクロールする必要があります。私はオンラインで検索し、WeChatのパブリックアカウントをクロールすることの難しさは、公式アカウント記事へのリンクをPC側に開くことができないことを発見しました。 WeChatのブラウザを使用する必要があります(WeChatクライアントによって補足されたパラメーターを取得した後、他のプラットフォームでのみ開くことができます)。これは、クローラープログラムに大きなトラブルを引き起こします。その後、私はZhihuの大物によって書かれたWeChatの公式アカウントクロールプログラムを見て、ボスのアイデアに直接続き、それをJavaに変えました。変換中に多くの詳細な問題に遭遇したので、共有します。
システムの基本的なアイデアは、AndroidエミュレータでWeChatを実行し、エミュレータのプロキシを設定し、プロキシサーバーを介してWeChatデータをインターセプトし、取得したデータを独自のプログラムに送信することです。
準備する必要がある環境:nodejs、anyproxyプロキシ、およびAndroidエミュレーター
nodejsダウンロードアドレス:http://nodejs.cn/download/。 Windowsバージョンをダウンロードして、直接インストールするだけです。インストール後、C:/プログラムファイル/nodejs/npm.cmdを実行すると、環境が自動的に構成されます。
AnyProxyインストール:前のステップに従ってnodejsをインストールした後、npmインストール-g anyproxyをCMDに直接実行してインストールします
オンラインでAndroidエミュレーターに行くだけです。
まず、プロキシサーバーの証明書をインストールします。 AnyProxyは、デフォルトでHTTPSリンクを解決しません。証明書をインストールした後、解決できます。 CMDでanyProxy -Rootを実行して証明書をインストールします。その後、この証明書をエミュレータにダウンロードする必要があります。
次に、プロキシサービスを開くために、anyProxy -Iコマンドを入力します。 (パラメーターを追加することを忘れないでください!)
このIPとポートを覚えておいてください、そして、Androidエミュレーターのエージェントがこれを使用します。ブラウザを使用してWebページを開きます:http:// localhost:8002/これは、HTTP送信データの表示に使用されるAnyproxyのWebインターフェイスです。
上の赤いボックスのメニューをクリックすると、QRコードがリリースされます。 Androidエミュレーターを使用してコードをスキャンして識別します。エミュレータ(携帯電話)は証明書をダウンロードしてインストールするだけです。
これで、エミュレータのプロキシを設定する準備ができました。プロキシメソッドはマニュアルに設定されています。プロキシIPは任意のプロキシマシンを実行するIPであり、ポートは8001です
準備作業は基本的にここで完了します。エミュレータでWeChatを開き、パブリックアカウントで記事を開くと、開いたばかりのWebインターフェイスからanyProxyによってキャプチャされたデータが表示されます。
WeChatの記事へのリンクは、上の赤い箱にあります。クリックして特定のデータを表示します。応答本体に何もない場合、証明書のインストールに問題があります。
上記のすべてが完了した場合、歩き続けることができます。
ここでは、WeChatデータをキャプチャするためにプロキシサービスに依存していますが、データを取得してWeChatを自分で操作することはできません。手動でコピーする方が良いです。したがって、WeChatクライアントは単独でページにジャンプする必要があります。現時点では、任意のプロキシを使用してWeChatサーバーによって返されたデータをインターセプトし、ページジャンプコードをITに挿入し、処理されたデータをシミュレータに返してWeChatクライアントの自動ジャンプを実現できます。
AnyProxyでRule_Default.jsというJSファイルを開きます。 Windowsの下のファイルは次のとおりです。C:/users/administrator/appdata/roaming/npm/node_modules/anyproxy/lib
ファイルには、fallserverresdataasync:function(req、res、serverresdata、callback)と呼ばれる方法があります。この方法は、AnyProxyによって取得されたデータに対してさまざまな操作を実行する責任があります。最初は、コールバック(serverresdata)のみが必要です。このステートメントは、サーバーの応答データをクライアントに直接返すことを意味します。このステートメントを直接削除し、Daniuが作成した次のコードに置き換えます。ここでコードに変更を加えたことはありません。そのコメントは非常に明確に説明されています。ロジックに従って直接読むだけで、大きな問題はありません。
function(req、res、serverresdata、callback){if(/mp//getmassendmsg/i.test(req.url)){//リンクアドレスが公式アカウントの履歴メッセージページ(ファーストページフォーム)//console.log(最初のページcrawl "); if(serverresdata.tostring()!== ""){6 try {//エラーがプログラムの終了から終了するのを防ぐvar reg =/msglist =(。*?);/;履歴メッセージの通常のマッチングルール= ret = reg.exec(serverresdata.tostring()); httppost(ret [1]、req.url、 "/internetspider/getData/showbiz"); //この関数は後で定義され、一致する履歴メッセージjsonが独自のサーバーに送信されますvar http = require( 'http'); http.get( 'http:// xxx/getwxhis'、function(res){//このアドレスは独自のサーバー上のプログラムです。目的は、次のリンクアドレスを取得し、アドレスをJSスクリプトに配置し、次のページに自動的にジャンプし、getWxhis.phpの原則が後で紹介されます。 callback(chunk+serverresdata); //返されたコードを履歴メッセージページに挿入し、表示して表示する})}); } catch(e){//上記のレギュラーが一致しない場合、このページのコンテンツは、履歴メッセージの最初のページがHTML形式で、2番目のページはJSON形式であるため、公式アカウントの履歴メッセージページの2番目のページになります。 //CONSOLE.LOG("最初のページが下向きのフォームをクロールする "); try {var json = json.parse(serverresdata.toString()); if(json.general_msg_list!= []){httppost(json.general_msg_list、req.url、 "/xxx/showbiz"); callback(serverresdata); // 2番目のページJSONコンテンツに直接返します}} //console.log("最初のページクロールエンドのスタート "); } else if(/mp//profile_ext/?action=home/i.test(req.url)){//リンクアドレスが公式アカウントの履歴メッセージページ(2番目のページ形式)try {var reg =/var msglist =/'(.*?)/'hehry/ reg.exec(serverresdata.tostring()); //変数をstring httppost(ret [1]、req.url、 "/xxx/showbiz"); //この関数は後で定義され、それが独自のサーバーvar http = required( 'http'); http.get( 'xxx/getwxhis'、function(res){//このアドレスはサーバー上のプログラムです。目的は、次のリンクアドレスを取得し、アドレスをJSスクリプトに自動的にジャンプし、getwxhis.phpの原則を後で紹介します。履歴メッセージページと表示して表示})}); } catch(e){//console.log(e); callback(serverresdata); }} else if(/mp//profile_ext/?action=getmsg/i.test(req.url)){// 2番目のページ式json try {var json = json.parse(serverresdata.tostring()); if(json.general_msg_list!= []){httppost(json.general_msg_list、req.url、 "/xxx/showbiz"); } callback(serverresdata); } else if(/mp //getAppmsgext/i.test(req.url)){//リンクアドレスが公式アカウント記事のビューといいねの数といいね!{httppost(serverresdata、req.url、 "/xxx/getmsgext");サーバー} catch(e){} callback(serverresdata); } else if(/s/?__ biz/i.test(req.url)|| /mp//rumor/i.test(Req.url)) (//-リンクアドレスは公式アカウントの記事です(公式のアカウントの記事です)try {var http = required( 'http'); http.get( 'http:// xxx/getwxpost'、function(res){// })}); } catch(e){callback(serverresdata); }} else {callback(serverresdata); } // callback(serverresdata); }、ここで、WeChatの公式アカウントの履歴メッセージページへの2つの形式のリンクがあることをここで簡単に説明させてください:1つはmp.weixin.qq.com/mp/getmassendmsgで始まり、もう1つはmp.weixin.qq.com/mp/profile_extで始まります。履歴ページをひっくり返すことができます。ひっくり返った場合、JSイベントをトリガーして、JSONデータ(次のページのコンテンツ)を取得するリクエストを送信します。また、公式のアカウント記事のリンクや、読み取りやいいね!これらのリンクの形式は固定されており、論理的な判断によって区別できます。ここに質問があります:すべての歴史ページをrawった場合の方法。私のアイデアは、JSを介して滑り落ちるマウスをシミュレートすることで、リストの次の部分をロードするリクエストを送信するリクエストをトリガーすることです。または、任意のプロキシを直接使用して、スライディングロードのリクエストを分析し、この要求をWeChatサーバーに直接生成します。しかし、残りのデータがないと判断する方法には問題があります。私は最新のデータをrawっていますが、当面はこの要件を持っていません。将来それを望んでいるかもしれません。必要な場合は、試すことができます。
次の図は、上記のhttppostメソッドの内容です。
関数httppost(str、url、path){// jsonをサーバーに送信し、strはjsonコンテンツ、urlは履歴メッセージページアドレス、パスは受信プログラムのパスとファイル名です
console.log( "転送を開始");
試す{
var http = require( 'http');
var data = {
str:ecodeuricomponent(str)、
url:ecodeuricoponent(url)
};
data = require( 'querystring')。stringify(data);
var options = {
方法:「投稿」、
ホスト: "xxx"、// http://はないことに注意してください。これはサーバーのドメイン名です。
ポート:xxx、
パス:パス、//受信プログラムのパスとファイル名
ヘッダー:{
'Content-Type': 'Application/x-www-form-urlencoded; charset = utf-8 '、
「コンテンツレングス」:data.length
}
};
var req = http.request(options、function(res){
Res.SetEncoding( 'utf8');
res.on( 'data'、function(chunk){
console.log( 'body:' + chunk);
});
});
req.on( 'error'、function(e){
console.log( '要求の問題:' + e.message);
});
req.write(data);
req.end();
} catch(e){
console.log( "エラーメッセージ:"+e);
}
console.log( "転送操作の終了");
}上記の作業を行った後、次のステップは、自分のビジネスに従ってサーバーコードを完了することです。当社のサービスは、プロキシサーバーが処理のために送信したデータを受信し、永続的な操作を実行し、同時にWeChatに注入する必要があるJSコードをプロキシサーバーに送信するために使用されます。プロキシサーバーによって傍受されたいくつかの異なるリンクから送信されたデータの場合、これらのデータを処理するために対応するメソッドを設計する必要があります。 anyProxyのJS WeChatデータを処理する方法からfunction(req、res、serverresdata、callback)を処理する方法から、公式アカウント履歴ページデータ、公式アカウントページデータ、公式アカウントの記事のいいね、読み取りデータを設計するために少なくとも3つの方法が必要であることがわかります。同時に、クロールタスクを生成し、公式アカウントの往復クロールを完了する方法を設計する必要があります。より多くのデータをクロールする必要がある場合は、AnyProxyによってキャプチャされたリンクからより多くの必要なデータを分析し、次にJudgentErserverresdataasync:function(req、res、serverresdata、コールバック)に判断を追加し、必要なデータをインターセプトして独自のサーバーに送信し、対応するメソッドを追加して、このタイプのデータを処理します。
Javaでサーバーコードを書いています。
公式アカウント履歴ページデータを処理する方法:
public void getMSGJSON(String str、string url)unsupportedencodingExceptionをスローする{// todo auto-enerated method stist string biz = ""; map <string、string> querystrs = httpurlparser.parseurl(url); if(querystrs!= null){biz = querystrs.get( "__ biz"); biz = biz + "=="; } /***データベースからのクエリbizが既に存在するかどうか、存在しない場合は挿入します。 *これは、コレクションターゲットに新しい公式アカウントを追加したことを意味します。 */ list <weixin> results = weixinmapper.selectbybiz(biz); if(results == null || results.size()== 0){weixin weixin = new weixin(); weixin.setbiz(biz); weixin.setcollect(system.currenttimemillis()); weixinmapper.insert(weixin); } //system.out.println(str); // parse str変数リスト<オブジェクト> lists = jsonpath.read(str、 "['list']"); for(オブジェクトリスト:リスト){object json = list; int type = jsonpath.read(json、 "['comm_msg_info'] ['type']"); if(type == 49){// type = 49は、テキストメッセージ文字列content_url = jsonpath.read(json、 "$ .app_msg_ext_info.content_url");であることを意味します。 content_url = content_url.replace( "//"、 "").replaceall( "amp;"、 ""); //テキストメッセージのリンクアドレスを取得int is_multi = jsonpath.read(json、 "$ .app_msg_ext_info.is_multi"); // 「$ .comm_msg_info.datetime」 if(content_url!= null &&! ""。equals(content_url)){tmplist tmplist = new tmplist(); tmplist.setcontenturl(content_url); tmplistmapper.insertsectiontective(tmplist); }} catch(Exception e){system.out.println( "キューは既に存在し、挿入されていません!"); } / ***ここでは、$ content_url* / list <post> postlist = postmapper.selectbyContenturl(content_url)に基づいてデータベース投稿から繰り返されるかどうかを判断します。 boolean contenturlexist = false; if(postlist!= null && postlist.size()!= 0){contenturlexist = true; } if(!contenturlexist){// '同じ$ content_urlがデータベース投稿に存在する' integer fileid = jsonpath.read(json、 "$ .app_msg_ext_info.fileid"); urlencoder.encode(title、 "utf-8"); String Digest = jsonPath.Read(JSON、 "$ .APP_MSG_EXT_INFO.DIGEST"); //記事概要String source_url = jsonpath.read(json、 "$ .App_msg_ext_info.source_url");文字列= jsonpath.read(json、 "$ .app_msg_ext_info.cover"); //カバー画像cover = cover.replace( "//"、 ""); /***データベースに保存* /// System.out.println( "title:"+title); // system.out.println( "wechat id:"+fileid); // System.out.println( "記事概要:"+Digest); // System.out.Out.Println( "+surce_urlln("+source_url);アドレス:「+カバー); post post = new Post(); post.setbiz(biz); post.settitle(title); post.settitleencode(title_encode); post.setfieldId(fileID); post.setDigest(Digest); post.setsourceurl(source_url); post.setCover(カバー); post.setistop(1); //それを見出しのコンテンツとしてタグ付けするpost.setismulti(is_multi); post.setdatime(datetime); post.setcontenturl(content_url); postmapper.insert(post); } if(is_multi == 1){//それがマルチグラフィックメッセージリスト<object> multilists = jsonpath.read(json、 "['app_msg_ext_info'] ['multi_app_msg_item_list']"); for(Object Multilist:Multilist){Object Multijson = Multilist; content_url = jsonpath.read(multijson、 "['content_url']")。toString()。 list <post> posts = postmapper.selectbyContenturl(content_url); if(post!= null && posts.size()!= 0){contenturlexist = true; } if(!contenturlexist){// '同じ$ content_urlはデータベースに存在しません'/** *ここに、グラフィックとテキストメッセージのリンクアドレスを取得キューライブラリに挿入します *(キューライブラリは後で紹介されます。 null &&! ""。equals(content_url)){tmplist tmplistt = new tmplist(); tmplistt.setContenturl(content_url); tmplistmapper.insertsectiontive(tmplistt); } string title = jsonpath.read(multijson、 "$ .title");文字列ittitle_encode = urlencoder.encode(title、 "utf-8"); integer fileid = jsonpath.read(multijson、 "$ .fileid"); string digest = jsonpath.read(multijson、 "$ .digest"); string source_url = jsonpath.read(multijson、 "$ .source_url"); source_url = source_url.replace( "//"、 "");文字列cover = jsonpath.read(multijson、 "$ .cover"); cover = cover.replace( "//"、 ""); // system.out.println( "title:"+title); // system.out.println( "wechat id:"+fileid); // system.out.println( "記事概要:"+ダイジェスト); // system.out.println( "元のリンクを読む:"+source_url); post post = new Post(); post.setbiz(biz); post.settitle(title); post.settitleencode(title_encode); post.setfieldId(fileID); post.setDigest(Digest); post.setsourceurl(source_url); post.setCover(カバー); post.setistop(0); //タグ見出しのコンテンツpost.setismulti(is_multi); post.setdatime(datetime); post.setcontenturl(content_url); postmapper.insert(post); }}}}}}}}}}公式アカウントの記事ページへの対処方法:
public String getWXPost(){// TODO自動生成メソッドスタブ / ***現在のページが公式のアカウント記事ページである場合、このプログラムを読む*最初にコレクションキューリストで行のload = 1を削除します*次に、キューリストから「ID ASCによる注文」に従って複数の行を選択します(このラインは上記のプログラムとは異なることに注意してください)* / tmplistmapper.deleteryboy(1);リスト<Tmplist> queues = tmplistmapper.selectmany(5);文字列url = ""; if(queues!= null && queues.size()!= 0 && queues.size()> 1){tmplist queue = queues.get(0); url = queue.getContenturl(); queue.setisload(1); int result = tmplistmapper.updatebyprimarykey(queue); System.out.println( "result:"+result); } else {system.out.println( "getpost queues is null?"+queues == null:queues.size()); weixin weixin = weixinmapper.selectone();文字列biz = weixin.getBiz(); if((math.random()> 0.5?1:0)== 1){url = "http://mp.weixin.qq.com/mp/getmasssendmsg?__biz=" + biz + "#wechat_webview_type = 1&wechat_redirect"; "https://mp.weixin.qc.com/mp/profile_ext?action=home&_biz=" + biz + "#wechat_redirect"; //公式アカウントのhistorificメッセージのURLアドレスを分割する(2番目のページ形式)} 「#wechat_redirect "; //公式アカウントの履歴メッセージ(2番目のページフォーム)のURLアドレスを分割します//現在のタイムスタンプに記載されている公式アカウントテーブルの収集時間フィールドを更新します。 weixin.setcollect(system.currenttimemillis()); int result = weixinmapper.updatebyprimarykey(weixin); system.out.println( "getpost weixin updateresult:"+result); } int randomtime = new Random()。nextint(3) + 3; string jscode = "<script> setimeout(function(){window.location.href = '"+url+"';}、"+randomtime*1000+"); </script>"; jscodeを返します。 }公式アカウントのいいね!
public void getmsgext(string str、string url){// todo auto-eneratedメソッドスタブstring biz = "";文字列sn = ""; map <string、string> querystrs = httpurlparser.parseurl(url); if(querystrs!= null){biz = querystrs.get( "__ biz"); biz = biz + "=="; sn = querystrs.get( "sn"); sn = "%" + sn + "%"; } /** * $ sql = "select * from` article table`ここで `biz` = '"。$ biz。 "' * and` content_url` like '% "。$ sn。"%' "limit 0,1; * biz and sn/ post post = postmapper.selectbybizandsn(biz、sn)に基づいて対応する記事を見つけます。 if(post == null){system.out.println( "biz:"+biz); System.out.println( "sn:"+sn); tmplistmapper.deleteByload(1);戻る; } // system.out.println( "json data:"+str); integer read_num; integer like_num; {read_num = jsonpath.read(str、 "['appmsgstat'] ['read_num']") System.out.println( "read_num:"+read_num); System.out.println( "vike_num:"+like_num); System.out.println(e.getMessage()); } /***ここで、対応する記事はSNに基づいてコレクションキューリストで削除されます。つまり、この記事はコレクションキューから削除できます。 * $ sql = "content_url` like '%"。$ sn。 "%'" */ tmplistmapper.deletebysn(sn); //次に、ビューの数を更新して、記事の表に気づきます。 post.setreadnum(read_num); post.setlikenum(like_num); postmapper.updatebyprimarykey(post); }WeChatインジェクションへのジャンプを処理する方法JS:
public string getwxhis(){string url = ""; // TODO自動生成方法スタブ /***現在のページがパブリックアカウントの履歴メッセージである場合、このプログラムを読む*コレクションキューリストにロードフィールドがあります。値が1に等しい場合、それは読み取られていることを意味します*最初にコレクションキューリストで行ロード= 1を削除します*次に、チームリストから任意の行を選択します*/ tmplistmapper.deleteByload(1); tmplist queue = tmplistmapper.selectrandomone(); system.out.println( "queue is null?"+queue); if(queue == null){//キューリストは空です/***キューリストが空の場合、公式アカウントを保存するテーブルからBIZを取得します。 *ここでは、公式アカウントテーブルに収集時間の時間フィールドを設定します。正の順序でソートした後、 *最小のタイムスタンプで公式アカウントの記録を取得し、そのbiz */ weixin weixin = weixinmapper.selectone()を取得します。文字列biz = weixin.getBiz(); url = "https://mp.weixin.qq.com/mp/profile_ext?action=home &_biz =" + biz + "#wechat_redirect"; //公式アカウント履歴メッセージ(2番目のページフォーム)//コレクション時間フィールドの更新公式アカウントテーブルのコレクション時間フィールドweixin.setcollect(system.currenttimemillis()); int result = weixinmapper.updatebyprimarykey(weixin); system.out.println( "gethis weixin updateresult:"+result); } else {//現在の行のcontent_urlフィールドを取得url = queue.getContenturl(); //ロードフィールドを1 tmplistmapper.updatebycontenturl(url)に更新します。 } //次の$ URLをJSスクリプトにリダイレクトするように変更し、AnyProxyによってWeChatページに注入します。 // echo "<script> setimeout(function(){window.location.href = '"。$ url。 "';}、2000); </script>"; int randomtime = new Random()。nextint(3) + 3; string jscode = "<script> setimeout(function(){window.location.href = '"+url+"';}、"+randomtime*1000+"); </script>"; jscodeを返します。 }上記は、プロキシサーバーによって傍受されるデータを処理するプログラムです。ここに注意を払う必要がある問題があります。このプログラムは、データベースに含まれる各公式アカウントへのラウンドロビンアクセスを実施し、保存された記事でさえ再びアクセスします。目的は、記事の意見の数と同類を更新し続けることです。多数のパブリックアカウントをクロールする必要がある場合は、タスクキューを追加して条件付き制限を追加するためにコードを変更することをお勧めします。それ以外の場合、公式アカウントは複数のラウンドとサイクルで複製データをクロールし、効率に大きく影響します。
この時点で、WeChat公式アカウントのすべての記事リンクがrawいされ、このリンクは永久に有効であり、ブラウザで開くことができます。次に、クローラープログラムを作成して、データベースから記事のコンテンツやその他の情報をクロールします。
私はWebMagicで書かれたクローラーで、軽量で使いやすいです。
パブリッククラスのSpidermodelはPageProcessorを実装しています{private static postmapper postmapper;プライベート静的リスト<post>投稿。 //エンコード、クロール間隔、再試行時間などを含むクロールウェブサイトの関連する構成public site getSite(){// todo auto-enerated method stub return this.site; } public void Process(ページページ){// todo auto-enerated method stub post post = posts.remove(0); string content = page.gethtml()。xpath( "// div [@id = 'js_content']")。get(); //ハリーの記事はここで決定されます。直接削除レコードがある場合、または表現ビットを設定して記事が調和していることを示す場合、(content == null){system.out.println( "記事は調和しています!"); //POSTMAPPER.DELETEBYPRIMARYKEY(post.getId());戻る; } string contentsnap = content.replaceall( "data-src"、 "src")。 page.gethtml()。xpath( "// div [@id = 'meta_content']");文字列pubtime = null;文字列wxname = null;文字列著者= null; if(metacontent!= null){pubtime = metacontent.xpath( "// em [@id = 'post-date']")。get(); if(pubtime!= null){pubtime = htmltoword.striphtml(pubtime); //記事公開時間} wxname = metacontent.xpath( "// a [@id = 'post-user']")。get(); if(wxname!= null){wxname = htmltoword.striphtml(wxname); // publicアカウント名}著者= metacontent.xpath( "// em [ @class = 'rich_media_meta rich_media_meta_text'および@id!= 'post-date']"); if(author!= null){著者= htmltoword.striphtml(著者); // stysted著者}} // system.out.println( "publish time:"+pubtime); // system.out.println( "publicアカウント名:"+wxname); // system.out.out.out.out.out.out.out.out.out. string title = post.getTitle()。代替品( "" ""、 ""); //記事タイトル文字列= post.getDigest(); //記事概要int likenum = post.getlikenum(); wechatinfobean(); wechatbean.settitle(title); wechatbean.setcontent(contenttxt); //プレーンテキストコンテンツwechatbean.setsourcode(contentsnap); // snapshot wechatbean.setlikecount(likenum); wechatbean.setviewcount(readnum); wechatbean.setabstractText(digest); // abstract wechatbean.seturl(contenturl); wechatbean.setpublishtime(pubtime); wechatbean.setsitename(wxname); //サイト名パブリックアカウント名wechatbean.setauthor(著者); wechatbean.setmediatype( "wechat公式アカウント"); //ソースメディアタイプwechatstorage.savewechatinfo(wechatbean); //タグ記事はrawったpost.setispider(1); postmapper.updatebyprimarykey(post); } public static void startspider(list <post> inposts、postmapper mypostmapper、string ... urls){long starttime、endtime; starttime = system.currenttimemillis(); postmapper = mypostmapper;投稿=インポスト; httpclientdownloader httpclientdownloader = new httpclientdownloader(); spidermodel spidermodel = new spidermodel(); spider myspider = spider.create(spidermodel).addurl(urls); myspider.setDownLoader(httpClientDownLoader); try {spidermonitor.instance()。レジスタ(myspider); myspider.thread(1).run(); } catch(jmexception e){e.printstacktrace(); } endtime = system.currenttimemillis(); System.out.println( "Crawl Time" +((endtime-starttime) / 1000) + "秒 - "); }}他の無関係なロジックストレージコードを投稿しません。ここでは、MySQLのプロキシサーバーによってキャプチャされたデータを配置し、MongoDBのCrawlerプログラムによってrawうデータを保存しました。
以下は、あなたがクロールした公式のアカウント番号に関する情報です。