최근에 WeChat 공식 계정의 기사 정보를 기어 다닐 필요가 있습니다. 온라인으로 검색 한 결과 WeChat 공개 계정을 크롤링하는 데 어려움이있는 것은 공식 계정 기사에 대한 링크를 PC 측에서 열 수 없다는 것입니다. WeChat의 자체 브라우저를 사용해야합니다 (WeChat 클라이언트가 보충 한 매개 변수를 얻은 후에 만 다른 플랫폼에서만 열 수 있음). 이것은 크롤러 프로그램에 큰 문제를 일으킨다. 나중에, 나는 Zhihu의 큰 사람이 쓴 WeChat 공식 계정 크롤링 프로그램을보고 보스의 아이디어를 직접 따라 Java로 바꿨습니다. 전환 중에 많은 상세한 문제가 발생 했으므로 공유하겠습니다.
이 시스템의 기본 아이디어는 Android 에뮬레이터에서 WeChat을 실행하고 에뮬레이터의 프록시를 설정하고 프록시 서버를 통해 WeChat 데이터를 가로 채며 처리를 위해 얻은 데이터를 자체 프로그램으로 보내는 것입니다.
준비 해야하는 환경 : Nodejs, Anyproxy Proxy 및 Android 에뮬레이터
nodejs 다운로드 주소 : http://nodejs.cn/download/. Windows 버전을 다운로드 한 후 직접 설치하십시오. 설치 후 C :/Program Files/Nodejs/NPM.CMD를 실행하면 환경이 자동으로 구성됩니다.
Anyproxy 설치 : 이전 단계에 따라 Nodejs를 설치 한 후 CMD에서 직접 NPM 설치 -G AnyProxy를 실행하고 설치하십시오.
안드로이드 에뮬레이터 온라인으로 가십시오.
먼저 프록시 서버의 인증서를 설치하십시오. AdeProxy는 기본적으로 HTTPS 링크를 해결하지 않습니다. 인증서를 설치 한 후에는 해결할 수 있습니다. 인증서를 설치하려면 CMD에서 alyproxy -root를 실행하십시오. 그런 다음 에뮬레이터 에서이 인증서를 다운로드해야합니다.
그런 다음 프록시 서비스를 열려면 모든 프록시 -i 명령을 입력하십시오. (매개 변수를 추가해야합니다!)
이 IP와 포트를 기억하면 안드로이드 에뮬레이터의 에이전트가이를 사용합니다. 이제 브라우저를 사용하여 웹 페이지를 엽니 다. http : // localhost : 8002/이것은 http 전송 데이터를 표시하는 데 사용되는 모든 프록시의 웹 인터페이스입니다.
위의 빨간색 상자에서 메뉴를 클릭하면 QR 코드가 출시됩니다. 안드로이드 에뮬레이터를 사용하여 코드를 스캔하여 식별하십시오. 에뮬레이터 (휴대폰)는 인증서를 다운로드하여 설치합니다.
이제 에뮬레이터를위한 프록시를 설정할 준비가되었습니다. 프록시 방법은 매뉴얼로 설정됩니다. 프록시 IP는 모든 프록시 머신을 실행하는 IP이고 포트는 8001입니다.
준비 작업은 기본적으로 여기에서 완료됩니다. 에뮬레이터에서 WeChat을 열고 공개 계정에서 기사를 열면 방금 열린 웹 인터페이스에서 모든 프로파일로 캡처 한 데이터를 볼 수 있습니다.
WeChat 기사에 대한 링크는 위의 빨간색 상자에 있습니다. 특정 데이터를 보려면 클릭하십시오. 응답 본문에 아무것도 없다면 인증서 설치에 문제가 있습니다.
위의 모든 작업이 완료되면 계속 걸어갈 수 있습니다.
여기서 우리는 프록시 서비스에 의존하여 WeChat 데이터를 캡처하지만 데이터를 가져 와서 스스로 WeChat을 운영 할 수는 없습니다. 수동으로 복사하는 것이 좋습니다. 따라서 WeChat 클라이언트가 페이지 자체로 이동하려면 필요합니다. 이 시점에서는 모든 프록시를 사용하여 WeChat 서버가 반환 한 데이터를 가로 채고 페이지 점프 코드를 주입 한 다음 처리 된 데이터를 시뮬레이터로 반환하여 WeChat 클라이언트의 자동 점프를 달성 할 수 있습니다.
anyproxy에서 rule_default.js라는 JS 파일을 엽니 다. Windows의 파일은 다음과 같습니다
파일에는 ReplacesErverSdataSync : function (req, res, serverresdata, 콜백)이라는 메소드가 있습니다. 이 방법은 모든 프록시에서 얻은 데이터에 대한 다양한 작업을 수행하는 데 도움이됩니다. 처음에는 콜백 (ServerResData) 만 있어야합니다. 이 명령문은 서버 응답 데이터를 클라이언트에 직접 반환하는 것을 의미합니다. 이 명령문을 직접 삭제하고 Daniu가 작성한 다음 코드로 바꾸십시오. 여기서 코드를 변경하지 않았으며 그 의견은 매우 명확하게 설명됩니다. 논리에 따라 직접 읽으면 큰 문제가 없습니다.
replaceserverresdataasync : function (req, res, serverresdata, callback) {if (/mp//getmassendmsg/i.test (req.url)) {// 링크 주소가 공식 계정 히스토리 메시지 페이지 (첫 번째 페이지 양식) //console.log("Start 첫 페이지 크롤링 "); if (serverresdata.toString ()! == "") {6 try {// 오류가 프로그램을 종료하지 못하면 var reg =/msglist = (.*?); // 과거 메시지 정의 규칙적 일치 규칙을 정의합니다. httppost (ret [1], req.url, "/internetspider/getdata/showbiz"); //이 함수는 나중에 정의되어 일치하는 히스토리 메시지 json을 자체 서버 var http = require ( 'http')로 보냅니다. http.get ( 'http : // xxx/getwxhis', function (res) {//이 주소는 자체 서버의 프로그램입니다. 목적은 다음 링크 주소를 얻고 JS 스크립트에 주소를 배치하고 다음 페이지에 자동으로 이동하는 것입니다. getwxhis.php의 원리는 나중에 도입됩니다 ( '데이터', 기능. 콜백 (chunk+serverresdata); // 반환 된 코드를 히스토리 메시지 페이지에 삽입하고 표시로 반환}); } catch (e) {// 위의 규칙이 일치하지 않으면이 페이지의 내용이 공식 계정의 역사 메시지 페이지의 두 번째 페이지 일 수 있습니다. 히스토리 메시지의 첫 페이지는 HTML 형식이고 두 번째 페이지는 JSON 형식이기 때문입니다. //console.log("start 첫 번째 페이지는 아래쪽으로 기어 다니며 "); try {var json = json.parse (serverresdata.tostring ()); if (json.general_msg_list! = [])) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); //이 기능은 나중에 위와 같이 정의되어 두 번째 페이지의 json을 자신의 서버로 보내} catch (e) {console.log (e); // 오류 포괄적 인} Callback (ServerResData); // 두 번째 페이지 JSON Content}}} //console.log("start 첫 페이지 크롤링 종료 "); } else if (/mp//profile_ext/?action=home/i.test (req.url))) {// 링크 주소가 공식 계정 역사 메시지 페이지 (두 번째 페이지 양식) 시도 {var reg =/var msglist =/'(var reg =/var msglist = /'(///define historical 메시지의 정규 일치 규칙). reg.exec (serverresdata.toString ()); // 변수를 문자열로 변환 httppost (ret [1], req.url, "/xxx/showbiz"); //이 함수는 나중에 정의됩니다. 일치하는 히스토리 메시지 json을 자체 서버 var http = requess ( 'http')로 보내십시오. http.get ( 'xxx/getwxhis', function (res) {//이 주소는 서버의 프로그램입니다. 목적은 다음 링크 주소를 가져오고, JS 스크립트에 주소를 배치하고 다음 페이지로 자동 이동하는 것입니다. 히스토리 메시지 페이지에 코드를 작성하고 표시로 돌아갑니다})}); } catch (e) {//console.log(e); 콜백 (ServerResData); }} else if (/mp//profile_ext/? if (json.general_msg_list! = []) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); //이 함수는 나중에 위와 같이 나중에 정의되어 두 번째 페이지의 json을 자체 서버로 보내기 (e) catch (e) {console.log (e); } 콜백 (ServerResData); } else if (/mp//getAppmsgext/i.test (req.url))) {// 링크 주소가 공식 계정 기사에 대한 뷰 수와 좋아하는 경우 {httppost (serverresdata, req.url), "/xxx/getmsgext"); Server} catch (e) {} 콜백 (ServerResData); } else if (/s/? __ biz/i.test (req.url) || /mp//rumor/i.test(req.url)) {///////4 링크 주소가 공식 계정 기사 (소문 주소는 공식 계정 기사, 거부 됨) try {var http = requess ( 'http'); http.get ( 'http : // xxx/getwxpost', function (res) {//이 주소는 서버의 또 다른 프로그램입니다. 목적은 다음 링크 주소를 가져오고, 주소를 JS 스크립트에 배치하고 다음 페이지로 자동 이동하는 것입니다. 나중에 Getwxpost.php의 원리가 도입됩니다 ( 'Data', Chunk (Chunk); })}); } catch (e) {콜백 (ServerResData); }} else {콜백 (ServerResData); } // 콜백 (ServerResData); },WeChat 공식 계정의 역사적 메시지 페이지에 대한 두 가지 형태의 링크가 있다고 간단히 설명하겠습니다. 하나는 mp.weixin.qq.com/mp/getmassendmsg로 시작하고 다른 하나는 mp.weixin.qq.com/mp/profile_ext로 시작합니다. 역사 페이지를 뒤집을 수 있습니다. 뒤집어지면 JS 이벤트가 트리거되어 JSON 데이터를 얻기위한 요청을 보냅니다 (다음 페이지의 내용). 공식 계정 기사 링크와 읽기 및 좋아하는 기사 수 (JSON 데이터 반환)에 대한 링크도 있습니다. 이러한 링크의 형태는 고정되어 있으며 논리적 판단으로 구별 될 수 있습니다. 여기에는 질문이 있습니다. 모든 역사 페이지를 크롤링 해야하는 경우해야합니다. 내 생각은 JS를 통해 미끄러짐을 시뮬레이션하여 목록의 다음 부분을로드하라는 요청을 제출하라는 요청을 트리거하는 것입니다. 또는 슬라이딩 로딩 요청을 분석 하고이 요청을 WeChat 서버에 직접 생성하기 위해 직접 모든 프로색을 사용하십시오. 그러나 남은 데이터가 없다고 판단하는 방법에는 문제가 있습니다. 나는 최신 데이터를 크롤링하고 있으며 당분간이 요구 사항이 없으며 앞으로도 원할 수도 있습니다. 필요하면 시도해 볼 수 있습니다.
다음 그림은 위의 httppost 방법의 내용입니다.
함수 httppost (str, url, path) {// JSON을 서버로 보내기
Console.log ( "전달 시작");
노력하다{
var http = 요구 ( 'http');
var data = {
STR : EncodeUricomponent (str),
URL : EncodeUricomponent (URL)
};
data = require ( 'querystring'). Stringify (data);
var 옵션 = {
방법 : "post",
호스트 : "xxx", // http : //가 없으며, 이것은 서버의 도메인 이름입니다.
포트 : xxx,
경로 : 경로, // 수신 프로그램의 경로 및 파일 이름
헤더 : {
'Content-Type': 'Application/X-www-form-urlencoded; charset = utf-8 ',
"컨텐츠 길이": 데이터
}
};
var req = http.request (옵션, 함수 (res) {
res.setencoding ( 'utf8');
res.on ( 'data', function (chunk) {
Console.log ( 'body :' + chunk);
});
});
req.on ( 'error', function (e) {
console.log ( '요청과 관련된 문제 :' + e.message);
});
req.write (데이터);
req.end ();
} catch (e) {
console.log ( "오류 메시지 :"+e);
}
Console.log ( "전달 작업 종료");
}위의 작업을 수행 한 후 다음 단계는 자신의 비즈니스에 따라 서버 코드를 완료하는 것입니다. 당사의 서비스는 처리를 위해 프록시 서버에서 보낸 데이터를 수신하고, 지속적인 작업을 수행하고, 동시에 WeChat에 주입 해야하는 JS 코드를 프록시 서버로 보내야합니다. 프록시 서버에서 가로 채는 여러 링크에서 전송 된 데이터의 경우 이러한 데이터를 처리하기 위해 해당 방법을 설계해야합니다. WeChAT 데이터를 처리하는 모든 Proxy의 JS 방법에서 eplaceserverresdataasync : function (req, res, serverresdata, 콜백)에서 공식 계정 기록 페이지, 공식 계정 기사 데이터, 공식 계정 기사를 좋아하고 읽기 데이터를 설계하기 위해 최소한 세 가지 방법이 필요하다는 것을 알 수 있습니다. 동시에, 우리는 크롤링 작업을 생성하고 공식 계정의 왕복 크롤링을 완료하는 방법을 설계해야합니다. 더 많은 데이터를 크롤링 해야하는 경우, 모든 프록시가 캡처 한 링크에서 더 필요한 데이터를 분석 한 다음, 판결을 추가하여 기능 (REQ, RES, ServerResData, Callback)을 대체하고 필요한 데이터를 가로 채고 해당 방법을 추가하여 서버 에서이 유형의 데이터를 처리 할 수 있습니다.
Java에서 서버 코드를 작성하고 있습니다.
공식 계정 기록 페이지 데이터 처리 방법 :
public void getmsgjson (문자열 str, 문자열 URL)은 unsupportedencodingexception {// todo 자동 생성 메소드 스터브 스트링 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 variable list <bood> lists = jsonpath.read (str, "[ 'list']"); for (Object List : Lists) {Object JSON = LIST; int type = jsonpath.read (json, "[ 'comm_msg_info'] [ 'type']"); if (type == 49) {// type = 49는 문자 메시지 문자열 컨텐츠 _sonpath.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"); // jsonpatime (jsonputime)입니다. "$ .comm_msg_info.dateTime"); // 이미지 및 문자 메시지 보내기 시간을 보내십시오/** * 이미지 및 문자 메시지 링크 주소는 획득 대기열 라이브러리 tmplist *에 삽입됩니다 (대기열 라이브러리는 나중에 소개됩니다. 주된 목적은 배치 획득 큐를 설정하는 것입니다. ! = null |& "". tmplist.setContentUrl (content_url); tmplistmapper.insertselective (tmplist); }} catch (예외 e) {system.out.println ( "큐는 이미 삽입되지 않고 존재합니다!"); } / *** 여기서 우리는 $ content_url* / list <ostlist> postlist = postMapper.SelectByContEntUrl (content_url)을 기반으로 데이터베이스 게시물에서 반복되는지 판단합니다. 부울 contenturlexist = false; if (postList! = null && postList.Size ()! = 0) {contentUrlexist = true; } if (! contenturlexist) {// '데이터베이스 게시물에 동일한 $ content_url이'Integer fileId = jsonpath.read (json, "$ .app_msg_ext_info.fileid"); // wechat id String = jsonpath.read (json, "$ .app_msg_ext_info.title"); // urlencoder.encode (제목, "UTF-8"); String digest = jsonpath.read (json, "$ .app_msg_ext_info.digest"); // article summary string source_url = jsonpath.read (json, "$ .app_msg_ext_info.source_url"); // "//"); "); 문자열 cover = jsonpath.read (json, "$ .app_msg_ext_info.cover"); // 표지 이미지 표지 = cover.replace ( "//", ""); /*** 데이터베이스에 저장* /// system.out.println ( "title :"+title); // system.out.println ( "wechat id :"+fileId); // system.out.println ( "article summary :"+digest); // system.out.println ( "+source_url); 주소 : "+덮개); 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 (표지); post.setistop (1); // 헤드 라인 내용으로 태그를 게시합니다. post.setismulti (is_multi); post.setdateTime (dateTime); post.setContentUrl (content_url); postmapper.insert (post); } if (is_multi == 1) {// multi-graphic 메시지 목록 인 경우 <botorpilists = 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 (). replace ( "//", "") .replaceall ( "amp;", "," "); // 그래픽 메시지 링크/*** 여기서 데이터베이스가 $ content_url을 기반으로 반복되는지 판단 할 것인지 orrors*/contenturlexist를 피할 것입니다. list <post> posts = postmapper.selectbyContentUrl (content_url); if (posts! = null && posts.size ()! = 0) {contentUrlexist = true; } if (! contentUrlexist) {// '// 동일한 $ content_url은 데이터베이스에 존재하지 않습니다.'/** * 여기, 그래픽 및 문자 메시지 링크 주소를 획득 큐 라이브러리 *에 삽입합니다. (대기열 라이브러리는 나중에 소개됩니다. 주된 목적은 배치 획득 대기열을 설정하는 것입니다. &&! "". tmplistt.setContentUrl (content_url); tmplistmapper.insertselective (tmplistt); } 문자열 제목 = jsonpath.read (Multijson, "$ .Title"); String titling_encode = urlencoder.encode (title, "utf-8"); 정수 fileId = jsonpath.read (Multijson, "$ .fileid"); 문자열 다이제스트 = jsonpath.read (Multijson, "$ .Digest"); 문자열 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 ( "article summary :"+digest); // system.out.println ( "원래 링크 :"+source_url); system.out.out.println ( "+system.out.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 (표지); post.setistop (0); // 태그는 헤드 라인 내용이 아닙니다. post.setismulti (is_multi); post.setdateTime (dateTime); post.setContentUrl (content_url); postmapper.insert (post); }}}}}}}}}}공식 계정 기사 페이지를 다루는 방법 :
공개 문자열 getwxpost () {// todo 자동 생성 메소드 스터브 / *** 현재 페이지가 공식 계정 기사 페이지 인 경우이 프로그램을 읽으 면서이 프로그램을 읽습니다* 먼저 큐어 목록에서 "id asc"에 따라 여러 줄을 선택합니다. 목록 <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 (큐); System.out.println ( "업데이트 결과 :"+결과); } else {system.out.println ( "getPost 큐는 null?"+queues == null? null : queues.size ()); weixin weixin = weixinmapper.selectone (); 문자열 비즈 = 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_redipe"; = "https://mp.weixin.qq.com/mp/profile_ext?action=home& __biz=" + biz + "#wechat_redirect"; // 공식 계정 historical 메시지의 URL 주소를 분할하십시오 (두 번째 페이지 양식)} url = "https://mp.weixin.qqq.c.com/mp/profile _ext=hime. + biz + "#wechat_redirect"; // 공식 계정의 URL 주소를 분할 (두 번째 페이지 양식) // 지금 언급 한 공식 계정 테이블의 수집 시간 시간 필드를 현재 시간 스탬프로 업데이트하십시오. weixin.setCollect (System.CurrentTimeMillis ()); int result = weixinmapper.updatebyprimarykey (weixin); System.out.println ( "getPost weixin updateresult :"+result); } int randomtime = new random (). NextInt (3) + 3; 문자열 jscode = "<cript> settimeout (function () {wind jscode를 반환합니다. }공식 계정의 좋아요 및 읽기 수를 다루는 방법 :
public void getmsgext (String str, String URL) {// todo 자동 생성 메소드 스터브 스트링 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 = "`jicre`grict`biz` = '". $ biz. " * and`content_url'like '%". "%'"제한 0,1; * 비즈 및 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; 정수와 같은 _num; try {read_num = jsonpath.read (str, "[ 'appmsgstat'] [ 'read_num']"); // volume like_num = jsonpath.read (str, "[ 'appmsgstat']] [ 'like_num']"); // like Volume (read_num = 123; // like _ 321; System.out.println ( "read_num :"+read_num); System.out.println ( "like_num :"+like_num); System.out.println (e.getMessage ()); } /*** 여기에서, 해당 기사는 SN을 기반으로 컬렉션 큐 목록에 삭제됩니다. 즉,이 기사는 컬렉션 큐에서 제거 될 수 있음을 의미합니다. * $ sql = "`team list '에서 삭제`content_url` loke'%". $ sn. "%'" */ tmplistmapper.deletebysn (sn); // 그런 다음 기사 테이블에 뷰와 좋아하는 뷰 수를 업데이트하십시오. post.setreadnum (read_num); post.setlikenum (like_num); postmapper.updatebyprimarykey (post); }WeChat 주입 JS 로의 점프를 처리하는 방법 :
공개 문자열 getwxhis () {문자열 url = ""; // todo 자동 생성 메소드 스터브 /*** 현재 페이지가 공개 계정 히스토리 메시지 인 경우이 프로그램을 읽으십시오* 수집 큐 목록에로드 필드가 있습니다. 값이 1과 같으면 읽는 것을 의미합니다* 먼저 컬렉션 큐 목록에서 라인 부하 = 1을 삭제 한 다음 팀 목록에서 모든 줄을 선택하십시오*/ tmplistmapper.deleteByload (1); tmplist queue = tmplistmapper.selectrandomone (); System.out.println ( "큐는 null?"+queue); if (queue == null) {// 큐 목록이 비어 있습니다/*** 큐 목록이 비어 있으면 공식 계정 비즈를 저장하는 테이블에서 비즈를 가져옵니다. * 여기서는 공식 계정 테이블에서 수집 시간의 시간 필드를 설정했습니다. 긍정적 인 순서로 정렬 한 후 * 가장 작은 타임 스탬프로 공식 계정의 기록을 얻고 BIZ */ weixin weixin = weixinmapper.selectone (); 문자열 비즈 = weixin.getBiz (); url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&_biz=" + biz + "#wechat_redirect"; // 공식 계정 historical 메시지 URL 주소 (두 번째 페이지 양식)를 분할하십시오. 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 스크립트로 리디렉션하고 모든 프록시에 의해 WeChat 페이지에 주입합니다. // eCHO "<Script> settimeout (function () {window.location.href = '". $ url. "';}, 2000); </script>"; int randomtime = new random (). NextInt (3) + 3; 문자열 jscode = "<cript> settimeout (function () {wind jscode를 반환합니다. }위는 프록시 서버에서 가로 채는 데이터를 처리하는 프로그램입니다. 여기에주의를 기울여야하는 문제가 있습니다. 이 프로그램은 데이터베이스에 포함 된 각 공식 계정에 대한 라운드 로빈 액세스를 수행하며 저장된 기사조차 다시 액세스 할 수 있습니다. 목적은 기사의 뷰와 좋아요를 계속 업데이트하는 것입니다. 많은 수의 공개 계정을 크롤링 해야하는 경우 작업 대기열을 추가하고 조건부 제한을 추가하기 위해 코드를 수정하는 것이 좋습니다. 그렇지 않으면 공식 계정은 여러 라운드에서 복제 데이터를 크롤링하고 사이클은 효율성에 큰 영향을 미칩니다.
이 시점에서 WeChat 공식 계정의 모든 기사 링크가 크롤링 되었으며이 링크는 영구적으로 유효하며 브라우저에서 열 수 있습니다. 다음으로 Crawler 프로그램을 작성하여 데이터베이스의 기사 내용 및 기타 정보를 크롤링하십시오.
저는 WebMagic으로 작성된 크롤러입니다. 가볍고 사용하기 쉽습니다.
공개 클래스 SPIDERMODEL은 PageProcessor {private static postmapper postmapper; 개인 정적 목록 <ost> 게시물; // 인코딩, 크롤링 간격, 재 시도 시간 등을 포함한 크롤링 웹 사이트의 관련 구성. 개인 사이트 사이트 = site.me (). SetRetrytimes (3) .SETSEPTIME (100); 공개 사이트 getSite () {// todo 자동 생성 메소드 스텁 return this.site; } public void process (페이지 페이지) {// todo 자동 생성 메소드 스터브 포스트 Post = posts.remove (0); 문자열 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"). replaceall ( "preview.html", "player.html"); // snapshot string contenttxt = htmltoword.striphtml (// plain text contacontent = page.gethtml (). xpath ( "// div [@id = 'meta_content']"); 문자열 pubtime = null; 문자열 wxname = null; 문자열 author = null; 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); // public acc if (author! = null) {author = htmltoword.striphtml (author); // article author}} // system.out.println ( "publish time :"+pubtime); // system.out.println ( "공개 계정 이름 :"+wxname); // system.out.println (기사 저자 : "+저자); 문자열 제목 = post.getTitle (). replaceall ( "", ""); // article title string digest = post.getDigest (); // 기사 요약 int vicenum = post.getlikenum (); // article intreadnum = post.getReadnum (// article weChatBean = post.getContenturl); 새로운 wechatinfobean (); wechatbean.settitle (제목); wechatbean.setContent (contenttxt); // 일반 텍스트 컨텐츠 wechatbean.setSourcecode (contentsNap); // snapshot wechatbean.setlikecount (okenum); wechatbean.setViewCount (readnum); wechatbean.setabstracttext (digest); // acpract wechatbean.seturl (contenturl); wechatbean.setpublishtime (pubtime); wechatbean.setsiteName (wxname); // 사이트 이름 공개 계정 이름 wechatbean.setauthor (저자); wechatbean.setMediatype ( "wechat 공식 계정"); // 소스 미디어 유형 wechatstorage.savewechatinfo (wechatbean); // 기사가 기어 들어간 Post.setissPider (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 = 새로운 httpclientdownloader (); SPIDERMODEL SPIDERMODEL = 새로운 SPIDERMODEL (); Spider myspider = Spider.create (SpiderModel) .addurl (urls); MySpider.SetDownloader (httpclientdownloader); try {spidermonitor.instance (). Register (myspider); myspider.thread (1) .run (); } catch (jmexception e) {e.printstacktrace (); } endTime = System.CurrentTimeMillis (); System.out.println ( "크롤링 타임" + ((EndTime-StartTime) / 1000) + "Seconds-"); }}다른 관련없는 논리 저장 코드를 게시하지 않겠습니다. 여기에 MySQL에 프록시 서버가 캡처 한 데이터를 넣고 MongoDB의 Crawler 프로그램에 의해 크롤링 된 데이터를 저장했습니다.
아래는 기어온 공식 계정 번호에 대한 정보입니다.