في الآونة الأخيرة ، أحتاج إلى زحف معلومات المقالة الخاصة بحساب WeChat الرسمي. لقد بحثت عبر الإنترنت ووجدت أن صعوبة تزحف حسابات WeChat العامة هي أنه لا يمكن فتح رابط المقالة الرسمية على جانب الكمبيوتر. يجب أن نستخدم متصفح WeChat الخاص (يمكنك فتحه فقط على منصات أخرى بعد الحصول على المعلمات التي تستكملها عميل WeChat). هذا يسبب مشكلة كبيرة في برنامج الزاحف. في وقت لاحق ، رأيت برنامجًا للزحف على حساب WeChat الذي كتبه رجل كبير على Zhihu ، وتبعت فكرة الرئيس مباشرة وحولتها إلى Java. واجهت العديد من المشكلات التفصيلية أثناء التحول ، لذلك سأشاركه.
تتمثل الفكرة الأساسية للنظام في تشغيل WeChat على محاكي Android ، وإعداد وكيل للمحاكي ، واعتراض بيانات WeChat من خلال خادم الوكيل ، وإرسال البيانات التي تم الحصول عليها إلى برنامجك الخاص للمعالجة.
البيئات التي يجب إعدادها: Nodejs ، anyproxy proxy ، ومحاكي Android
NODEJS عنوان تنزيل: http://nodejs.cn/download/. قمت بتنزيل إصدار Windows ، فقط قم بتثبيته مباشرة. بعد التثبيت ، سيقوم تشغيل ملفات C:/البرنامج/nodejs/npm.cmd تلقائيًا بتكوين البيئة.
تثبيت anyproxy: بعد تثبيت nodejs وفقًا للخطوة السابقة ، قم بتشغيل NPM تثبيت -G anyproxy مباشرة في CMD وتثبيت
فقط اذهب إلى Android Emulator عبر الإنترنت ، والكثير منهم.
أولاً ، قم بتثبيت شهادة خادم الوكيل. anyproxy لا يحل رابط HTTPS افتراضيا. بعد تثبيت الشهادة ، يمكن حلها. تنفيذ anyproxy -الجذر في CMD لتثبيت الشهادة. بعد ذلك ، يجب عليك تنزيل هذه الشهادة في المحاكي.
ثم أدخل أمر anyproxy -i لفتح خدمة الوكيل. (تذكر أن تضيف معلمات!)
تذكر هذا IP والمنفذ ، ثم يستخدم وكيل محاكي Android هذا. استخدم الآن متصفحك لفتح صفحة الويب: http: // localhost: 8002/هذا هو واجهة الويب الخاصة بـ anyproxy ، والتي يتم استخدامها لعرض بيانات نقل HTTP.
انقر على القائمة في المربع الأحمر أعلاه وسيتم إصدار رمز الاستجابة السريعة. استخدم محاكي Android لمسح الرمز لتحديده. سيقوم المحاكي (الهاتف المحمول) بتنزيل الشهادة وتثبيتها فقط.
أنت الآن مستعد لإعداد وكيل للمحاكي. تم تعيين طريقة الوكيل على يدوي. IP الوكيل هو IP الذي يعمل على جهاز anyproxy ، والمنفذ 8001
يتم الانتهاء من عمل التحضير هنا. افتح WeChat على المحاكي وفتح مقالًا على حساب عام ، ويمكنك رؤية البيانات التي تم التقاطها بواسطة anyproxy من واجهة الويب التي فتحتها للتو:
الرابط إلى مقالة WeChat موجود في المربع الأحمر أعلاه. انقر في رؤية البيانات المحددة. إذا لم يكن هناك شيء في هيئة الاستجابة ، فهناك مشكلة في تثبيت الشهادة.
إذا تم كل ما سبق ، يمكنك الاستمرار في السير.
نعتمد هنا على خدمات الوكيل لالتقاط بيانات WeChat ، لكن لا يمكننا الحصول على جزء من البيانات وتشغيل WeChat من قبل أنفسنا. من الأفضل نسخها يدويًا. لذلك نحن بحاجة إلى عميل WeChat للقفز إلى الصفحة بمفرده. في هذا الوقت ، يمكنك استخدام anyproxy لاعتراض البيانات التي يتم إرجاعها بواسطة خادم WeChat ، وضخ رمز القفز في الصفحة ، ثم إرجاع البيانات المعالجة إلى المحاكاة لتحقيق القفزة التلقائية لعميل WeChat.
افتح ملف JS يسمى Rule_Default.js في anyproxy. الملف أسفل Windows هو: C:/المستخدمون/المسؤول/APPDATA/ROAMING/NPM/NODE_MODULES/anyproxy/lib
هناك طريقة تسمى PLADESERVERRESDATAASYNC: الدالة (REQ ، RES ، ServerResData ، رد الاتصال) في الملف. هذه الطريقة هي المسؤولة عن إجراء عمليات مختلفة على البيانات التي حصلت عليها anyproxy. في البداية ، يجب أن يكون هناك رد اتصال فقط (ServerResData) ؛ يعني هذا البيان إرجاع بيانات استجابة الخادم مباشرة إلى العميل. احذف هذا البيان مباشرة واستبدله بالرمز التالي الذي كتبه Daniu. لم أقم بإجراء أي تغييرات على الكود هنا ، ويتم شرح التعليقات الموجودة فيه بوضوح شديد. فقط اقرأها مباشرة وفقًا للمنطق ، وليس هناك مشكلة كبيرة.
placeserReverResDataAsync: Function (REQ ، RES ، ServerresData ، Callback) {if (/mp//getmassendmsg/i.test (req.url)) {// عندما يكون عنوان الارتباط هو صفحة الرسائل التاريخية الرسمية (نموذج الصفحة الأولى) //console.log (""STartart first page ") ؛ if (serverresData.ToString ()! == "") {6 حاول {// منع الأخطاء من الخروج من البرنامج var reg =/msglist = (. httppost (ret [1] ، req.url ، "/internetspider/getData/showbiz") ؛ // يتم تعريف هذه الوظيفة لاحقًا ، وإرسال الرسالة التاريخية المطابقة إلى الخادم الخاص بها var http = require ('http') ؛ http.get ('http: // xxx/getwxhis' ، function (res) {// هذا العنوان هو برنامج على خادمه الخاص. والغرض من ذلك هو الحصول على عنوان الرابط التالي ، وضع العنوان في برنامج نصي JS ، ويقفز تلقائيًا إلى الصفحة التالية. Callback (chunk+serverresdata) ؛ // أدخل الكود الذي تم إرجاعه في صفحة الرسائل التاريخية والعودة لعرضه})}) ؛ } catch (e) {// إذا لم يتطابق المعتاد أعلاه ، فقد يكون محتوى هذه الصفحة هو الصفحة الثانية لصفحة الرسائل التاريخية للحساب الرسمي ، لأن الصفحة الأولى من الرسالة التاريخية هي بتنسيق HTML ، والصفحة الثانية بتنسيق JSON. //console.log(" الصفحة الأولى الزحف لأسفل ") ؛ حاول {var json = json.parse (serverResData.ToString ()) ؛ if (json.general_msg_list! = []) {httppost (json.general_msg_list ، req.url ، "/xxx/showbiz") ؛ // يتم تعريف هذه الوظيفة لاحقًا على النحو الوارد أعلاه ، وإرسال json من الرسالة التاريخية الثانية إلى الخادم الخاص بك}}} Callback (ServerResData) ؛ // العودة مباشرة إلى الصفحة الثانية JSON Content}}} //console.log("start نهاية الزحف في الصفحة الأولى ") ؛ } آخر إذا (/mp//profile_ext/؟action=home/i.test (req.url)) {// عندما يكون عنوان الارتباط هو صفحة الرسائل التاريخية للحساب الرسمي (نموذج الصفحة الثانية) حاول {var reg =/var msglist = /'m ( reg.exec (serverresdata.toString ()) ؛ // تحويل المتغير إلى سلسلة httppost (ret [1] ، req.url ، "/xxx/showbiz") ؛ // يتم تعريف هذه الوظيفة لاحقًا ، أرسل رسالة تاريخية مطابقة إلى خادمها الخاص var http = require ('http') ؛ http.get ('xxx/getwxhis' ، function (res) {// هذا العنوان هو برنامج على الخادم الخاص بك. والغرض من ذلك هو الحصول على عنوان الرابط التالي ، وضع العنوان في برنامج نصي JS ، ويقفز تلقائيًا إلى الصفحة التالية. رمز في صفحة الرسالة التاريخية والعودة لعرضها})}) ؛ } catch (e) {//console.log(e) ؛ رد الاتصال (ServerResData) ؛ }} آخر إذا (/mp//profile_ext/؟action=getMsg/i.test (req.url)) {// تعبير الصفحة الثانية json try {var json = json.parse (serverresdata.tostring ()) ؛ if (json.general_msg_list! = []) {httppost (json.general_msg_list ، req.url ، "/xxx/showbiz") ؛ // يتم تعريف هذه الوظيفة لاحقًا على النحو الوارد أعلاه ، وإرسال json من الرسالة التاريخية الثانية إلى خادمها الخاص}}} } رد الاتصال (serverResData) ؛ } آخر إذا (/mp//getappmsgext/i.test (req.url)) {// عندما يكون عنوان الرابط هو عدد المشاهدات والأعجوبة لمقالة الحساب الرسمي ، جرب {httppost (serverresdata ، req.url ، "/xxx/getmsgext") ؛ server} catch (e) {} callback (serverResData) ؛ } آخر إذا (/s/؟ __ biz/i.test (req.url) || /mp//rumor/i.test(req.url)) {/when عنوان الرابط هو المقالة الرسمية (عنوان الشائعات هو المقالة الرسمية ، لقد تم رفضها) حاول {var http = require ('http') ؛ http.get ('http: // xxx/getwxpost' ، function (res) {// هذا العنوان هو برنامج آخر على الخادم الخاص بك. والغرض من ذلك هو الحصول على عنوان الرابط التالي ، وضع العنوان في برنامج نصي JS ، والانتقال تلقائيًا إلى الصفحة التالية. })}) ؛ } catch (e) {callback (serverResData) ؛ }} آخر {callback (serverResData) ؛ } // callback (serverResData) ؛ } ،اسمحوا لي أن أشرح باختصار هنا أن هناك شكلين من الروابط إلى صفحة الرسائل التاريخية للحسابات الرسمية لـ WeChat: يبدأ أحدهما بـ mp.weixin.qq.com/mp/getmassendmsg ، والآخر يبدأ بـ mp.weixin.qq.com/mp/profile_ext. يمكن قلب صفحة التاريخ. إذا انقلبت ، فسيؤدي ذلك إلى إحداث حدث JS لإرسال طلب للحصول على بيانات JSON (محتوى الصفحة التالية). هناك أيضًا روابط لمقال الحساب الرسمي ، بالإضافة إلى روابط إلى عدد المقالات التي تقرأها وإعجاباتها (إرجاع بيانات JSON). يتم إصلاح أشكال هذه الروابط ويمكن تمييزها بالحكم المنطقي. هناك سؤال هنا: كيف تفعل إذا كانت جميع صفحات التاريخ بحاجة إلى الزحف. فكرتي هي محاكاة الماوس المنزلق من خلال JS ، مما يؤدي إلى تشغيل طلب إرسال طلب لتحميل الجزء التالي من القائمة. أو استخدم anyproxy مباشرة لتحليل طلب التحميل المنزلق وإنشاء هذا الطلب مباشرة إلى خادم WeChat. ولكن هناك مشكلة في كيفية الحكم على أنه لا توجد بيانات متبقية. أنا أزحف أحدث البيانات ، وليس لدي هذا المطلب في الوقت الحالي ، وقد أريدها في المستقبل. إذا كنت في حاجة إليها ، يمكنك تجربتها.
الشكل التالي هو محتوى طريقة httppost أعلاه.
وظيفة httppost (str ، url ، path) {// إرسال json إلى الخادم ، str هو محتوى json ، url هو عنوان صفحة الرسالة التاريخية ، المسار هو المسار واسم ملف لبرنامج الاستلام
console.log ("ابدأ توجيه") ؛
يحاول{
var http = require ('http') ؛
بيانات var = {
STR: EncodeUricomponent (STR) ،
عنوان URL: EncodeUricomponent (URL)
} ؛
Data = require ('QueryString'). stringify (data) ؛
خيارات var = {
الطريقة: "بعد" ،
المضيف: "xxx" ، // لاحظ أنه لا يوجد http: // ، هذا هو اسم المجال للخادم.
المنفذ: xxx ،
المسار: المسار ، // مسار واسم الملف لبرنامج الاستلام
الرؤوس: {
"نوع المحتوى": "التطبيق/x-www-form-urlencoded ؛ charset = utf-8 '،
"طول المحتوى": Data.Length
}
} ؛
var req = http.request (الخيارات ، الدالة (الدقة) {
Res.SetEncoding ('Utf8') ؛
res.on ('Data' ، function (chunk) {
console.log ('body:' + chunk) ؛
}) ؛
}) ؛
req.on ('خطأ' ، الدالة (e) {
console.log ('مشكلة مع الطلب:' + e.message) ؛
}) ؛
req.write (البيانات) ؛
req.end () ؛
} catch (e) {
console.log ("رسالة خطأ:"+e) ؛
}
console.log ("إعادة التوجيه تنتهي") ؛
}بعد القيام بالعمل أعلاه ، فإن الخطوة التالية هي إكمال رمز الخادم وفقًا لعملك الخاص. يتم استخدام خدمتنا لتلقي البيانات التي يتم إرسالها بواسطة خادم الوكيل للمعالجة ، وأداء العمليات المستمرة ، وفي الوقت نفسه ، أرسل رمز JS الذي يحتاج إلى حقنه في WeChat إلى خادم الوكيل. بالنسبة للبيانات المرسلة من عدة روابط مختلفة تم اعتراضها بواسطة خادم الوكيل ، نحتاج إلى تصميم الطرق المقابلة لمعالجة هذه البيانات. من طريقة JS من anyproxy لمعالجة بيانات WeChat بدائل erceserResDataAsync: الدالة (REQ ، RES ، ServerresData ، رد الاتصال) ، يمكننا أن نعرف أن هناك حاجة إلى ثلاث طرق على الأقل لتصميم بيانات صفحة سجل الحساب الرسمية ، بيانات صفحة المقالة الرسمية ، مقالة الحساب الرسمية ، الإعجاب بالبيانات. في الوقت نفسه ، نحتاج أيضًا إلى تصميم طريقة لتوليد مهام الزحف وإكمال الزحف المستدير للحساب الرسمي. إذا كنت بحاجة إلى زحف المزيد من البيانات ، فيمكنك تحليل المزيد من البيانات التي تمس الحاجة إليها من الروابط التي تم التقاطها بواسطة anyproxy ، ثم إضافة حكم إلى استبدال eraceserResDataAsync: الوظيفة (REQ ، RES ، ServerresData ، رد الاتصال) ، واعتراض البيانات المطلوبة وإرسالها إلى الخادم الخاص بك ، وإضافة الطريقة المقابلة لمعالجة هذا النوع من البيانات على الخادم.
أنا أكتب رمز الخادم في Java.
طرق معالجة بيانات صفحة سجل الحساب الرسمية:
public void getMsgjson (String Str ، url url) يلقي UnduportedEncodingException {// todo method method method string biz = "" ؛ الخريطة <string ، string> QueryStrs = httpurlparser.parseurl (url) ؛ if (QueryStrs! = null) {biz = QueryStrs.get ("__ biz") ؛ biz = biz + "==" ؛ } /*** استعلام من قاعدة البيانات سواء كان Biz موجودًا بالفعل ، وأدخله إذا لم يكن موجودًا. * هذا يعني أننا أضفنا حسابًا رسميًا جديدًا لهدف التحصيل. */ list <Seixin> النتائج = weixinmapper.selectbybiz (biz) ؛ if (النتائج == null || النتائج. weixin.setbiz (biz) ؛ Weixin.setCollect (System.CurrentTimeMillis ()) ؛ weixinmapper.insert (Weixin) ؛ } //system.out.println(STR) ؛ // parse str fariable list <Object> siles = jsonpath.read (str ، "['list']") ؛ لـ (قائمة الكائنات: قوائم) {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 ، "$. "$ .comm_msg_info.dateTime") ؛ // إرسال وقت الصورة والرسالة النصية/** * هنا يتم إدراج عنوان ارتباط الصورة والرسالة النصية في مكتبة قائمة انتظار الاستحواذ tmplist * (سيتم تقديم مكتبة قائمة الانتظار لاحقًا. if (content_url! = null &&! ". tmplist.setContentUrl (content_url) ؛ tmplistmapper.InserTslective (tmplist) ؛ }} catch (استثناء e) {system.out.println ("قائمة الانتظار موجودة بالفعل ، ولم يتم إدخالها!") ؛ } / *** هنا نحكم على ما إذا كان يتم تكراره من منشور قاعدة البيانات استنادًا إلى $ content_url* / list <post> postlist = postmapper.selectbycontenturl (content_url) ؛ المحتوى المنطقي = false ؛ if (postlist! = null && postlist.size ()! = 0) {contentUrlexist = true ؛ } if (! contentUrlexist) {// 'نفس $ content_url موجود في post post post' Integer fileId = jsonpath.read (json ، "$ .app_msg_ext_info.fileid") ؛ urlencoder.encode (العنوان ، "UTF-8") ؛ String Digest = jsonpath.read (json ، "$ .App_MSG_EXT_INFO.DIGEST") ؛ // ملخص المقالة Source_url = jsonpath.read (json ، "$ .app_msg_ext_info.source_url") ؛ // اقرأ نص النص الأصلي = source_url.rle.repl.repl () غطاء السلسلة = jsonpath.read (json ، "$ .app_msg_ext_info.cover") ؛ // cover cover = cover.replace ("//" ، "") ؛ /*** حفظ إلى قاعدة البيانات* /// system.out.println ("العنوان:"+title) ؛ // system.out.println ("wechat id:"+fileId) ؛ // system.out.println ( العنوان: "+غطاء) ؛ post post = new post () ؛ post.setbiz (biz) ؛ post.settitle (العنوان) ؛ post.settitleencode (title_encode) ؛ post.setfieldid (fileId) ؛ post.setDigest (Digest) ؛ post.setsourceurl (source_url) ؛ post.setCover (cover) ؛ post.setiStop (1) ؛ // tag it as the headline content post.setismulti (is_multi) ؛ post.setDateTime (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']") ؛ لـ (كائن متعدد: multilists) {object multijson = multilist ؛ content_url = jsonpath.read (multijson ، "['content_url']"). toString (). استبدال ("//" ، "") .replaceall ("amp ؛" ، "" ") قائمة <post> posts = postmapper.selectbyContentUrl (content_url) ؛ if (posts! = null && posts.size ()! = 0) {contentUrlexist = true ؛ } if (! contentUrlexist) {// 'نفس $ content_url غير موجود في قاعدة البيانات'/** * هنا ، أدخل عنوان ارتباط الرسائل الرسومية والرسالة النصية في مكتبة قائمة انتظار الاستحواذ * (سيتم تقديم مكتبة قائمة الانتظار لاحقًا. null &&! " tmplistt.setContentUrl (content_url) ؛ tmplistMapper.InserTslective (tmplistt) ؛ } string title = jsonpath.read (multijson ، "$ .title") ؛ string title_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 Cover = jsonpath.read (multijson ، "$ .cover") ؛ cover = cover.replace ("//" ، "") ؛ // system.out.println ("title:"+title) ؛ // system.out.println ("wechat id:"+fileId) ؛ // system.out.println ("article summary: post post = new post () ؛ post.setbiz (biz) ؛ post.settitle (العنوان) ؛ post.settitleencode (title_encode) ؛ post.setfieldid (fileId) ؛ post.setDigest (Digest) ؛ post.setsourceurl (source_url) ؛ post.setCover (cover) ؛ post.setistop (0) ؛ // TAG ، ليس محتوى العنوان post.setismulti (is_multi) ؛ post.setDateTime (DateTime) ؛ post.setContentUrl (content_url) ؛ postmapper.insert (post) ؛ }}}}}}}}}كيفية التعامل مع صفحات مقالات الحساب الرسمية:
السلسلة العامة getwxpost () {// todo method method method stub / *** عندما تكون الصفحة الحالية هي صفحة المقالة الرسمية ، اقرأ هذا البرنامج* أولاً ، قم بحذف الخط = 1 في قائمة قائمة انتظار التجميع* ثم حدد خطوطًا متعددة وفقًا لـ "Order by ASC" من قائمة قائمة الانتظار (لاحظ أن هذا الخط يختلف عن البرنامج أعلاه)* / tmplistmper.deled.deletybload (1) ؛ قائمة <Tmplist> Queues = tmplistmapper.selectmany (5) ؛ url url = "" ؛ if (queues! = null && queues.size ()! = 0 && queues.size ()> 1) {tmplist queue = queues.get (0) ؛ url = queue.getContentUrl () ؛ Queue.SetIsload (1) ؛ int النتيجة = tmplistmapper.updateByPrimaryKey (قائمة الانتظار) ؛ System.out.println ("تحديث النتيجة:"+نتيجة) ؛ } آخر {system.out.println ("getPost queues هل null؟"+queues == null؟ 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 + " = "https://mp.weixin.qq.com/mp/profile_ext؟action=home&__biz=" + biz + "#wechat_redirect" ؛ // تقسيم عنوان عنوان URL للرسالة التاريخية الرسمية (نموذج الصفحة الثانية)}} biz + "#wechat_redirect" ؛ // قسمة عنوان عنوان URL للرسالة التاريخية للحساب الرسمي (نموذج الصفحة الثانية) // قم بتحديث حقل وقت التجميع في جدول الحساب الرسمي المذكور الآن إلى الطابع الزمني الحالي. Weixin.setCollect (System.CurrentTimeMillis ()) ؛ int النتيجة = weixinmapper.updateByPrimarykey (Weixin) ؛ System.out.println ("getPost Weixin UpdateResult:"+result) ؛ } int randomtime = new Random (). nextInt (3) + 3 ؛ String jScode = "<script> setTimeOut (function () {window.location.href = '"+url+"' ؛} ،"+randomtime*1000+") ؛ </script>" ؛ إرجاع JScode ؛ }كيفية التعامل مع عدد الإعجابات وقراءات الحسابات الرسمية:
public void getMsgext (String str ، url url) {// todo method method method string string = "" ؛ سلسلة SN = "" ؛ الخريطة <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. * ابحث عن المقالة المقابلة بناءً على biz و 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) ؛ عدد صحيح read_num ؛ عدد صحيح like_num ؛ حاول {read_num = jsonpath.read (str ، "['appmsgstat'] ['read_num']") ؛ // قراءة حجم like_num = jsonpath.read (str ، "['appmsgstat'] ['like_num'] System.out.println ("read_num:"+read_num) ؛ System.out.println ("like_num:"+like_num) ؛ System.out.println (E.GetMessage ()) ؛ } /*** هنا ، يتم حذف المقالة المقابلة أيضًا في قائمة قائمة انتظار التجميع بناءً على SN ، مما يعني أنه يمكن إزالة هذه المقالة من قائمة انتظار المجموعة. * $ sql = "delete from` team list `حيث" content_url` مثل "٪". $ sn. // ثم قم بتحديث عدد المشاهدات ويعجب إلى جدول المقال. post.setReadNum (read_num) ؛ post.setlikenum (like_num) ؛ postmapper.updateByprimaryKey (post) ؛ }كيفية التعامل مع القفز إلى WeChat Injection JS:
السلسلة العامة getWxHis () {String url = "" ؛ // TODO METRODATION METLOTY COB /*** عندما تكون الصفحة الحالية رسالة تاريخية للحساب العام ، اقرأ هذا البرنامج* يوجد حقل تحميل في قائمة قائمة انتظار التجميع. عندما تكون القيمة تساوي 1 ، فهذا يعني أنه يتم قراءتها* أولاً ، قم بحذف LIND LOAD = 1 في قائمة قائمة انتظار التجميع* ثم حدد أي سطر من قائمة الفريق*/ TMPLISTMAPPER.DELETEBYLOAD (1) ؛ Queue tmplist = tmplistMapper.SelectRandomone () ؛ system.out.println ("قائمة الانتظار هي null؟"+قائمة الانتظار) ؛ إذا كانت (Queue == NULL) {// قائمة الانتظار فارغة/*** إذا كانت قائمة قائمة الانتظار فارغة ، فاحصل على biz من الجدول الذي يخزن الحساب الرسمي biz. * هنا قمت بتعيين حقل زمني لوقت التحصيل في جدول الحساب الرسمي. بعد فرزه بترتيب إيجابي ، احصل على سجل الحساب الرسمي مع أصغر طابع زمني واحصل على biz */ weixin weixin = weixinmapper.selectone () ؛ سلسلة biz = weixin.getBiz () ؛ url = "https://mp.weixin.qq.com/mp/profile_ext؟action=home&__biz=" + biz + "#wechat_redirect" ؛ // قسمة عنوان URL للرسالة التاريخية (نموذج الصفحة الثانية) // تحديث حقل وقت التحصيل في جدول الحساب الرسمي المذكور الآن فقط إلى Timestamp الحالي. Weixin.setCollect (System.CurrentTimeMillis ()) ؛ int النتيجة = weixinmapper.updateByPrimarykey (Weixin) ؛ System.out.println ("Gethis Weixin Updateresult:"+result) ؛ } آخر {// احصل على حقل content_url من url السطر الحالي = queue.getContentUrl () ؛ // قم بتحديث حقل التحميل إلى 1 tmplistmapper.updateByContentUrl (url) ؛ } // قم بتغيير عنوان URL $ التالي لإعادة توجيهه إلى برنامج نصي JS وحقنه في صفحة WeChat بواسطة anyproxy. // echo "<script> setTimeOut (function () {window.location.href = '". $ url. "' ؛} ، 2000) ؛ </script>" ؛ int randomtime = new Random (). nextInt (3) + 3 ؛ String jScode = "<script> setTimeOut (function () {window.location.href = '"+url+"' ؛} ،"+randomtime*1000+") ؛ </script>" ؛ إرجاع JScode ؛ }ما سبق هو البرنامج الذي يعالج البيانات التي تم اعتراضها بواسطة خادم الوكيل. هناك مشكلة يجب الانتباه إلى هنا. سيقوم البرنامج بإمكانية الوصول إلى كل حساب رسمي مدرج في قاعدة البيانات ، وحتى المقالات المخزنة سيتم الوصول إليها مرة أخرى. والغرض من ذلك هو الاستمرار في تحديث عدد المشاهدات وأمثال المقالة. إذا كنت بحاجة إلى زحف عدد كبير من الحسابات العامة ، فمن المستحسن تعديل الكود لإضافة قوائم قوائم المهمة وإضافة قيود مشروطة. خلاف ذلك ، سوف يزحف الحساب الرسمي للبيانات المكررة في جولات متعددة وستؤثر الدورات بشكل كبير على الكفاءة.
في هذه المرحلة ، تم زحف جميع روابط المقالات الخاصة بحساب WeChat الرسمي ، وهذا الرابط صالح بشكل دائم ويمكن فتحه في المتصفح. بعد ذلك ، اكتب برنامج زاحف لزحف محتوى المقالة والمعلومات الأخرى من قاعدة البيانات.
أنا زاحف مكتوب في WebMagic ، إنه خفيف الوزن وسهل الاستخدام.
الطبقة العامة Spidermodel تنفذ PageProcessor {private static postmapper postmapper ؛ القائمة الثابتة الخاصة <post> المشاركات ؛ // التكوين ذي الصلة لموقع Crawl ، بما في ذلك الترميز ، فاصل الزحف ، أوقات إعادة المحاولة ، إلخ الموقع العام getSite () {// todo method method tuto clup return this.site ؛ } عملية void العامة (صفحة الصفحة) {// todo method method method method post = posts.remove (0) ؛ content string = page.gethtml (). xPath ("// div [@id = 'js_content']"). get () ؛ // مقالات هاري محددة هنا. إذا كان هناك سجل حذف مباشر أو تعيين بت التمثيل للإشارة إلى أن المقالة متناغمة إذا (المحتوى == null) {system.out.println ("المقالة متناغمة!") ؛ //postmapper.deleteByPrimaryKey (post.getId ()) ؛ يعود؛ } سلسلة contentsnap = content.replaceall ("data-src" ، "src"). replaceall ("معاينة. html" ، "player.html") ؛ page.gethtml (). xPath ("// div [@id = 'meta_content']") ؛ String PubTime = null ؛ سلسلة wxname = فارغة ؛ سلسلة مؤلف = فارغ ؛ if (metacontent! = null) {pubTime = metacontent.xpath ("// em [@id = 'post-date']"). get () ؛ if (pubTime! = null) {pubTime = htmltoword.striphtml (pubTime) ؛ // article publishing time} wxname = metacontent.xpath ("// a [@id = 'post-user']"). get () ؛ if (wxname! = null) {wxname = htmltoword.striphtml (wxname) ؛ // اسم الحساب العام} المؤلف = metacontent.xpath ("// em [ @class = 'rich_media_meta rich_media_meta_text' و @ if (uptor! = null) {effect = htmltoword.striphtml (uptor) ؛ // article effect}} // system.out.println ("publish time:"+pubtime) ؛ عنوان السلسلة = post.getTitle (). replaceall ("" ، "") ؛ // article title string digest = post.getDigest () ؛ // ملخص المقالة int likenum = post.getlikenum () ؛ = جديد wechatinfobean () ؛ WeChatbean.Settitle (العنوان) ؛ WeChatbean.setContent (contentTxt) ؛ // محتوى النص العادي wechatbean.setsourcecode (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) ؛ // علامة تم زحف المقالة post.setisspider (1) ؛ postmapper.updateByprimaryKey (post) ؛ ) startTime = system.currentTimeMillis () ؛ postmapper = myPostMapper ؛ المشاركات = inposts ؛ httpclientdownloader httpclientDownloader = جديد httpclientDownLoader () ؛ SpiderModel Spidermodel = new SpiderModel () ؛ Spider MySpider = Spider.create (SpiderModel) .addurl (urls) ؛ myspider.setDownloader (httpclientDownloader) ؛ حاول {Spidermonitor.instance (). التسجيل (MySpider) ؛ myspider.Thread (1) .run () ؛ } catch (jmexception e) {E.PrintStackTrace () ؛ } endtime = system.currentTimeMillis () ؛ System.out.println ("Crawl Time" + ((Endtime-StartTime) / 1000) + "Seconds--") ؛ }}لن أنشر رموز تخزين منطقية أخرى غير ذات صلة. لقد وضعت هنا البيانات التي تم التقاطها بواسطة خادم الوكيل في MySQL وتخزين البيانات التي تزحفها برنامج الزاحف الخاص بي في MongoDB.
فيما يلي معلومات حول رقم الحساب الرسمي الذي زحفته: