Recientemente, necesito rastrear la información del artículo de la cuenta oficial de WeChat. Busqué en línea y descubrí que la dificultad de rastrear cuentas públicas de WeChat es que el enlace al artículo de cuenta oficial no se puede abrir en el lado de la PC. Debemos usar el propio navegador de WeChat (solo puede abrirlo en otras plataformas después de obtener los parámetros complementados por el cliente WeChat). Esto causa grandes problemas para el programa Crawler. Más tarde, vi un programa de arrastre oficial de WeChat escrito por un tipo grande en Zhihu, y seguí directamente la idea del jefe y la convertí en Java. Encontré muchos problemas detallados durante la transformación, por lo que lo compartiré.
La idea básica del sistema es ejecutar WeChat en el emulador de Android, configurar un proxy para el emulador, interceptar datos de WeChat a través del servidor proxy y enviar los datos obtenidos a su propio programa para su procesamiento.
Entornos que deben estar preparados: NodeJs, cualquier proxy de proxy y emulador de Android
Dirección de descarga de NodeJS: http://nodejs.cn/download/. Descargué la versión de Windows, simplemente instálela directamente. Después de la instalación, ejecutar C:/Program Files/NodeJS/NPM.CMD configurará automáticamente el entorno.
Instalación de AnyProxy: después de instalar NodeJs de acuerdo con el paso anterior, ejecute NPM Instalar -G AnyProxy directamente en CMD e instalar
Simplemente vaya al emulador de Android en línea, muchos de ellos.
Primero, instale el certificado para el servidor proxy. AnyProxy no resuelve el enlace HTTPS de forma predeterminada. Después de instalar el certificado, se puede resolver. Ejecute AnyProxy -Root en CMD para instalar el certificado. Después de eso, debe descargar este certificado en el emulador.
Luego ingrese cualquier comando de cualquier proxy -i para abrir el servicio proxy. (¡Recuerde agregar parámetros!)
Recuerde esta IP y puerto, y luego el agente del emulador de Android lo usará. Ahora use su navegador para abrir la página web: http: // localhost: 8002/Esta es la interfaz web de AnyProxy, que se utiliza para mostrar datos de transmisión HTTP.
Haga clic en el menú en el cuadro rojo de arriba y se lanzará un código QR. Use el emulador de Android para escanear el código para identificarlo. El emulador (teléfono móvil) descargará el certificado y simplemente lo instalará.
Ahora está listo para configurar un proxy para el emulador. El método proxy está configurado en manual. El proxy IP es la IP que ejecuta cualquier máquina de dosproxy, y el puerto es 8001
El trabajo de preparación se completa básicamente aquí. Abra WeChat en el emulador y abra un artículo en una cuenta pública, y puede ver los datos capturados por AnyProxy de la interfaz web que acaba de abrir:
El enlace al artículo de WeChat está en el cuadro rojo anterior. Haga clic para ver los datos específicos. Si no hay nada en el cuerpo de respuesta, hay un problema con la instalación del certificado.
Si se hace todo lo anterior, puede continuar caminando hacia abajo.
Aquí confiamos en los servicios proxy para capturar los datos de WeChat, pero no podemos tomar un dato y operar WeChat por nosotros mismos. Es mejor copiarlo manualmente. Por lo tanto, necesitamos que el cliente WeChat salte a la página por sí mismo. En este momento, puede usar cualquier propoxy para interceptar los datos devueltos por el servidor WeChat, inyectar el código de salto de la página y luego devolver los datos procesados al simulador para lograr un salto automático del cliente WeChat.
Abra un archivo js llamado reglas_default.js en AnyProxy. El archivo en Windows es: c:/users/administrador/appdata/roaming/npm/node_modules/anyproxy/libb
Existe un método llamado ReplacesServerResDataAsync: function (REQ, RES, ServerRResData, Callback) en el archivo. Este método es responsable de realizar diversas operaciones en los datos obtenidos por AnyProxy. Al principio, solo debe haber devolución de llamada (ServerResData); Esta declaración significa devolver directamente los datos de respuesta del servidor al cliente. Elimine esta declaración directamente y reemplácela con el siguiente código escrito por Daniu. No he realizado ningún cambio en el código aquí, y los comentarios en él se explican muy claramente. Simplemente léelos directamente de acuerdo con la lógica, y no hay un gran problema.
ReplacesServerResDataAsync: function (req, res, serverresdata, callback) {if (/mp//getMassendmsg/i.test (req.url)) {// Cuando la dirección de enlace es la página de mensajes históricos de cuenta oficial (formulario de primera página) //console.log("start la primera página "); if (serverresData.ToString ()! == "") {6 try {// Evite que los errores salgan del programa var reg =/msglist = (.*?);/; // Definir mensajes históricos reglas de coincidencia regulares var = reg.exec (serverresdata.ToString ()) ;// Variable a cadena a cadena Httppost (ret [1], req.url, "/internetspider/getData/showbiz"); // Esta función se define más adelante, enviando el mensaje histórico coincidente JSON a su propio servidor var http = request ('http'); http.get ('http: // xxx/getwxhis', function (res) {// Esta dirección es un programa en su propio servidor. El propósito es obtener la siguiente dirección de enlace, colocar la dirección en un script js y saltar automáticamente a la página siguiente. El principio de getwxhis.php se introducirá más tarde. Res.on ('datos', función (CHUNK) {) Callback (Chunk+ServerResData); // Inserte el código devuelto en la página de mensajes históricos y regrese para mostrarlo})}); } Catch (e) {// Si el regular anterior no coincide, entonces el contenido de esta página puede ser la segunda página de la página de mensajes históricos de la cuenta oficial, porque la primera página del mensaje histórico está en formato HTML, y la segunda página está en formato JSON. //console.log("Star la primera página que se arrastra hacia abajo "); intente {var json = json.parse (serverresData.ToString ()); if (json.general_msg_list! = []) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); // Esta función se define más adelante como se indica anteriormente, enviando el JSON del mensaje histórico de la segunda página a su propio servidor}} Catch (e) {console.log (e); Callback (ServerResData); // Regrese directamente a la segunda página Contenido JSON}} //console.log("start el final de rastreo de la primera página "); } else if (/mp//profile_ext/?action=home/i.test (req.url))) {// Cuando la dirección de enlace es la página de mensajes históricos de cuenta oficial (el formulario de la segunda página) intente {var reg =/var msglist = /'(.*?)/' ;///define las reglas regulares de los mensajes históricos (diferentes de los mensajes históricos (diferentes de la primera página de la primera página) reg.exec (serverresData.ToString ()); // Convertir la variable a String httpPost (ret [1], req.url, "/xxx/showbiz"); // Esta función se define más adelante, envía el mensaje histórico coincidente JSON a su propio servidor var http = requerir ('http'); http.get ('xxx/getwxhis', function (res) {// Esta dirección es un programa en su servidor. El propósito es obtener la siguiente dirección de enlace, colocar la dirección en un script js y saltar automáticamente a la página siguiente. El principio de getwxhis.php se introducirá más adelante. Res.on ('data', function (Chunk) {llamado (chunk+CHUNK+CODETATA//INSERTADO la página del mensaje histórico y volver a mostrarla})}); } catch (e) {//console.log(e); devolución de llamada (ServerResData); }} else if (/mp//profile_ext/?action=getmsg/i.test (req.url)) {// La segunda expresión de página JSON intenta {var json = json.parse (serverresdata.tostring ()); if (json.general_msg_list! = []) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); // Esta función se define más adelante como se indicó anteriormente, enviando el JSON del mensaje histórico de la segunda página a su propio servidor}} Catch (e) {console.log (e); } devolución de llamada (ServerResData); } else if (/mp//getappmsgext/i.test (req.url))) {// Cuando la dirección de enlace es el número de vistas y me gusta para el artículo de cuenta oficial, intente {httppost (serverResData, req.url, "/xxx/getmsgext"); // La función está definida más tarde, y la función es para enviar JSON con el número de vistas y el artículo para el artículo para el artículo para el artículo para el artículo para el artículo para el artículo para los artículos para los artículos para el número de vistas para el número para el artículo para los artículos para el número para los artículos para los artículos para el número de vistas para el número para los artículos para los artículos para el número para los artículos para los artículos para el número de vistas para el número para los artículos para el número para los artículos para el número de vistas. servidor} catch (e) {} llamada de llamada (serverResData); } else if (/s/? __ biz/i.test (req.url) || /mp//rumor/i.test(req.url))///con la dirección de la cuenta oficial es el artículo oficial de la cuenta (la dirección de rumores es el artículo de cuenta oficial, se negó) intente {var http = requerir ('http'); http.get ('http: // xxx/getwxpost', function (res) {// Esta dirección es otro programa en su servidor. El propósito es obtener la siguiente dirección de enlace, colocar la dirección en una secuencia de comandos JS, y saltar automáticamente a la página siguiente. El principio de getwxpost.php se introducirá más tarde. Res.on ('datos', función (chunk) {callback (chunk (chunk+backback) })}); } catch (e) {Callback (ServerResData); }} else {Callback (ServerResData); } // Callback (ServerResData); },Permítanme explicar brevemente aquí que hay dos formas de enlaces a la página de mensajes históricos de las cuentas oficiales de WeChat: uno comienza con mp.weixin.qq.com/mp/getMassendMsg, y el otro comienza con mp.weixin.qq.com/mp/profile_ext. La página del historial se puede voltear. Si se voltea, activará el evento JS para enviar una solicitud para obtener datos JSON (el contenido de la página siguiente). También hay enlaces de artículo de cuenta oficial, así como enlaces a la cantidad de artículos leídos y me gusta (que devuelven datos JSON). Las formas de estos enlaces se fijan y se pueden distinguir mediante un juicio lógico. Aquí hay una pregunta: cómo hacerlo si todas las páginas de historia necesitan ser arrastradas. Mi idea es simular el mouse deslizándose hacia abajo a través de JS, lo que desencadena la solicitud de enviar una solicitud para cargar la siguiente parte de la lista. O use directamente cualquierproxy para analizar la solicitud de carga deslizante y generar directamente esta solicitud al servidor WeChat. Pero hay un problema con cómo juzgar que no hay datos restantes. Estoy arrastrando los últimos datos, y no tengo este requisito por el momento, y es posible que lo desee en el futuro. Si lo necesita, puede probarlo.
La siguiente figura es el contenido del método HttpPost anterior.
función httppost (str, url, ruta) {// Enviar JSON al servidor, STR IS JSON Content, URL es la dirección de página de mensaje histórica, la ruta es la ruta y el nombre del archivo del programa receptor
console.log ("comenzar a reenviar");
intentar{
var http = require ('http');
var data = {
STR: Codeuricomponent (STR),
URL: Encodeuricomponent (URL)
};
data = require ('QueryString'). Stringify (Data);
opciones var = {
Método: "Publicar",
Host: "xxx", // Tenga en cuenta que no hay http: //, este es el nombre de dominio del servidor.
Puerto: xxx,
ruta: ruta, // La ruta y el nombre del archivo del programa receptor
Encabezados: {
'Content-type': 'Application/x-www-form-urlencoded; charset = utf-8 ',
"Contenido-longitud": data.length
}
};
var req = http.request (opciones, function (res) {
res.setEncoding ('UTF8');
res.on ('Data', Function (Chunk) {
console.log ('Body:' + Chunk);
});
});
req.on ('error', function (e) {
console.log ('Problema con solicitud:' + E.Message);
});
req.write (datos);
req.end ();
} catch (e) {
console.log ("Mensaje de error:"+E);
}
console.log ("finalización de la operación de reenvío");
}Después de hacer el trabajo anterior, el siguiente paso es completar el código del servidor de acuerdo con su propio negocio. Nuestro servicio se utiliza para recibir datos enviados por el servidor proxy para su procesamiento, realizar operaciones persistentes y al mismo tiempo enviar el código JS que debe inyectarse a WeChat al servidor proxy. Para los datos enviados desde varios enlaces diferentes interceptados por el servidor proxy, necesitamos diseñar métodos correspondientes para procesar estos datos. Desde el método JS JS de Anyproxy para procesar los datos de WeChat reemplazar a los datos de los hechas: función (REQ, RES, ServerResData, devolución de llamada), podemos saber que se necesitan al menos tres métodos para diseñar los datos oficiales de la página del historial de cuentas, datos de la página del artículo de cuenta oficial, el artículo oficial de la cuenta me gusta y leer datos. Al mismo tiempo, también necesitamos diseñar un método para generar tareas de rastreo y completar el rastreo de ida y vuelta de la cuenta oficial. Si necesita rastrear más datos, puede analizar los datos más necesarios de los enlaces capturados por AnyProxy, y luego agregar un juicio a ReemplazarerResDataAsync: función (REQ, RES, ServerResData, Callback), interceptar los datos requeridos y enviarlo a su propio servidor, y agregar el método correspondiente para procesar este tipo de datos en el servidor.
Estoy escribiendo código del servidor en Java.
Métodos para procesar datos de la página del historial de cuenta oficial:
public void getMsgjson (String Str, String URL) lanza UnspportedEnCodingException {// TODO Método Generado automático String String biz = ""; MAP <String, String> Querystrs = httpurlparser.parseurl (url); if (queryStrs! = NULL) {biz = queryStrs.get ("__ biz"); biz = biz + "=="; } /*** Consulta de la base de datos si Biz ya existe, e inserte si no existe. * Esto significa que hemos agregado una nueva cuenta oficial para el objetivo de recolección. */ List <weixin> resultados = weixinmapper.selectbybiz (biz); if (resultados == null || results.size () == 0) {weixin weixin = new weixin (); weixin.setbiz (biz); weixin.setCollect (System.CurrentTimemillis ()); weixinmapper.insert (weixin); } //System.out.println(str); // PARSE STR LIST de la variable <ject> lists = jsonpath.read (str, "['list']"); for (lista de objetos: lists) {object json = list; int type = jsonpath.read (json, "['comm_msg_info'] ['type']"); if (type == 49) {// type = 49 significa que es una cadena de mensaje de texto content_url = jsonpath.read (json, "$ .app_msg_ext_info.content_url"); content_url = content_url.replace ("//", "") .replaceAll ("amp;", ""); // Obtenga la dirección de enlace del mensaje de texto int is_multi = jsonpath.read (json, "$ .app_msg_ext_info.is_multi"); // es un mensaje multicic en integer inteper integere (jsonpath.read.read.read.read.read (jsonpat. "$ .comm_msg_info.datetime"); // Enviar tiempo de imagen y mensaje de texto/** * Aquí la dirección de enlace de mensajes de imagen y texto se inserta en la biblioteca de colas de adquisición tmplist * (la biblioteca de cola se introducirá más adelante. El propósito principal es establecer una cola de adquisición, * Otro programa Otro programa de la próxima cuenta recopilada Según el contenido de la Oficina o Artículo Según el Contenido de la Otra de la Otra). if (content_url! = null &&! "". Equals (content_url)) {tmplist tmplist = new tmplist (); tmplist.setContentUrl (content_url); tmplistmapper.insertselective (tmplist); }} catch (Exception e) {System.out.println ("La cola ya existe, no se insertó!"); } / *** Aquí juzgamos si se repite desde la publicación de la base de datos basada en $ content_url* / list <s post> postlist = postmapper.selectbyContentUrl (content_url); boolean ContentURlexist = false; if (PostList! = NULL && PostList.Size ()! = 0) {ContentURExist = True; } if (! ContentURLEXIST) {// 'El mismo $ content_url existe en la base de datos post' Integer fileId = jsonPath.Read (json, "$ .App_Msg_ext_info.fileid"); // a WeChat id string string titlePath.read (json, "$ .app_msg_ext_info.title"); Urlencoder.encode (título, "UTF-8"); String Digest = jsonPath.Read (json, "$ .app_msg_ext_info.digest"); // Artículo Resumen String Source_url = JSONPath.Read (JSON, "$ .App_Msg_ext_info.Source_Url"); // Leer el enlace de texto original Source_url = fuente_url.Replace ("//", ""); ""); ");"); String Cover = jsonpath.read (json, "$ .app_msg_ext_info.cover"); // cover de imagen cubierta = cover.replace ("//", ""); /*** Guardar en la base de datos* /// System.out.println ("Title:"+Title); // System.out.Println ("WeChat Id:"+FileID); // System.Println ("Resumen del artículo:"+Digest); // System.out.println ("Lea el enlace original:"+Source_url); // System.out.out.out ("Cover Image. dirección: "+cubierta); Post post = new Post (); post.setBiz (biz); post.settitle (título); post.settitleEcode (title_encode); post.setFieldId (fileId); post.setDigest (digest); post.setSourceUrl (fuente_url); post.setCover (cubierta); post.setistop (1); // etiquételo como el contenido principal post.setismulti (is_multi); post.setDateTime (DateTime); post.setContentUrl (content_url); Postmapper.insert (post); } if (is_multi == 1) {// Si es una lista de mensajes multi-gráfica <ject> multilists = jsonpath.read (json, "['app_msg_ext_info'] ['multi_app_msg_item_list']"); for (object Multilist: Multilists) {Object MultiJson = Multilist; content_url = jsonpath.read (multijson, "['content_url']"). toString (). reemplazar ("//", "") .replaceall ("amp;", ""); // dirección de enlace de mensaje gráfico/*** aquí juzgaremos si la base de datos se repite en base a $ content_url para evitar errores*/contenturxist = falso; Lista <POST> POSTS = POSTMAPPER.SELECTBYCONTENTURL (content_url); if (publicar! = null && posts.size ()! = 0) {contentURLEST = true; } if (! ContentUrleSt) {// 'El mismo $ content_url no está presente en la base de datos'/** * aquí, inserte la dirección de enlace de mensaje gráfico y de texto en la biblioteca de colas de adquisición * (la biblioteca de cola se introducirá más adelante. null &&! "". Equals (content_url)) {tmplist tmplistt = new tmplist (); tmplistt.setContentUrl (content_url); tmplistmapper.insertselective (tmplistt); } Title de cadena = jsonpath.read (multijson, "$ .title"); Cadena title_encode = urlencoder.encode (título, "UTF-8"); Integer fileID = jsonpath.read (multijson, "$ .fileid"); String Digest = JsonPath.Read (MultiJson, "$ .digest"); String source_url = jsonpath.read (multijson, "$ .source_url"); fuente_url = fuente_url.replace ("//", ""); String cover = jsonpath.read (multijson, "$. .Cover"); cover = cover.replace ("//", ""); // System.out.println ("Título:"+Title); // System.out.println ("WeChat ID:"+FileID); // System.out.println ("Artículo Resumen:"+Digest); // System.out.Println ("Lea el enlace original:"+Source_Url); // System.Println ("Cubierta de la imagen:" Cubierta+"Cubierta); Post post = new Post (); post.setBiz (biz); post.settitle (título); post.settitleEcode (title_encode); post.setFieldId (fileId); post.setDigest (digest); post.setSourceUrl (fuente_url); post.setCover (cubierta); post.setistop (0); // etiqueta no es el contenido principal post.setismulti (is_multi); post.setDateTime (DateTime); post.setContentUrl (content_url); Postmapper.insert (post); }}}}}}}}}Cómo tratar con las páginas del artículo de cuenta oficial:
public String getWxPost () {// TODO Auto Generado Método STUB / *** Cuando la página actual es la página del artículo de cuenta oficial, lea este programa* Eliminar primero la carga de la línea = 1 en la lista de colas de cola* luego seleccione múltiples líneas de acuerdo con "orden por ID ASC" de la lista de colas (tenga en cuenta que esta línea es diferente del programa anterior)* / tmplistMapper. Lista <Tmplist> queues = tmplistMapper.SelectMany (5); Cadena url = ""; if (queues! = null && queues.size ()! = 0 && queues.size ()> 1) {tmplist queue = queues.get (0); url = queue.getContentUrl (); queue.setisload (1); int resultado = tmplistMapper.UpdateByPrimaryKey (cola); System.out.println ("Resultado de actualización:"+resultado); } else {System.out.println ("Las colas de getPost son nulos?"+colas == null? null: queues.size ()); Weixin weixin = weixinmapper.selectone (); Cadena 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.qq.com/mp/profile_ext?action=home&__biz=" + biz + "#wechat_redirect" ;/ biz + "#wechat_redirect"; // divide la dirección de URL del mensaje histórico de la cuenta oficial (el formulario de la segunda página) // Actualiza el campo de tiempo de recopilación en la tabla de cuenta oficial mencionada hace ahora a la marca de tiempo actual. weixin.setCollect (System.CurrentTimemillis ()); int resultado = weixinmapper.updateByPrimaryKey (weixin); System.out.println ("getPost weixin updaterSult:"+resultado); } int randomtime = new Random (). NextInt (3) + 3; String jscode = "<Script> setTimeOut (function () {window.location.href = '"+url+"';},"+randomtime*1000+"); </script>"; return jscode; }Cómo lidiar con la cantidad de me gusta y lecturas de las cuentas oficiales:
public void getMsgext (string str, string url) {// tODO método generado automático stub string biz = ""; Cadena sn = ""; MAP <String, String> Querystrs = httpurlparser.parseurl (url); if (queryStrs! = NULL) {biz = queryStrs.get ("__ biz"); biz = biz + "=="; sn = querytrs.get ("sn"); sn = "%" + sn + "%"; } /** * $ sql = "Seleccionar * de` Tabla de artículos 'donde `biz` ='". $ biz. "' * y` content_url` me gusta'%". $ sn."%'"Límite 0,1; * Encuentre el artículo correspondiente basado en biz y sn*/ post post = postmapper.selectbybizandsn (biz, sn); if (post == null) {system.out.println ("biz:"+biz); System.out.println ("Sn:"+Sn); tmplistMapper.DeleteByLoad (1); devolver; } // System.out.println ("Json Data:"+Str); Integer read_num; Entero como_num; Pruebe {read_num = jsonpath.read (str, "['appmsgstat'] ['read_num']"); // read volumen como_num = jsonpath.read (str, "['appmsgstat'] ['me gusta_num']"); // volumen} (excepción e) {read_num = 123; // como_num = 321; System.out.println ("read_num:"+read_num); System.out.println ("como_num:"+como_num); System.out.println (e.getMessage ()); } /*** Aquí, el artículo correspondiente también se elimina en la lista de columnas de colección basada en SN, lo que significa que este artículo se puede eliminar de la cola de colección. * $ sql = "eliminar de` equipo de equipo 'donde `content_url` me gusta'%". $ sn. "%'" */ tmplistmapper.deleteBysn (sn); // luego actualice el número de vistas y me gusta en la tabla de artículos. post.setReadnum (read_num); post.setLikenum (como_num); Postmapper.UpdateByPrimaryKey (post); }Cómo manejar la inyección de saltar a WeChat JS:
public String getwxhis () {string url = ""; // TODO Auto Generado Método STUB /*** Cuando la página actual es un mensaje histórico de cuenta pública, lea este programa* Hay un campo de carga en la lista de colas de colección. Cuando el valor es igual a 1, significa que se está leyendo* Eliminar primero la línea de carga = 1 en la lista de colas de colección* Luego seleccione cualquier línea de la lista de equipo*/ tmplistMapper.DeleteByLoad (1); Tmplist queue = tmplistMapper.Selectrandomone (); System.out.println ("La cola es nula?"+Cola); if (queue == null) {// La lista de colas está vacía/*** Si la lista de colas está vacía, obtenga un negocio de la tabla que almacene la cuenta oficial de la cuenta. * Aquí establecí un campo de tiempo del tiempo de recolección en la tabla de cuenta oficial. Después de ordenarlo en orden positivo, * obtenga el registro de la cuenta oficial con la marca de tiempo más pequeña y obtenga su biz */ weixin weixin = weixinmapper.selectone (); Cadena biz = weixin.getBiz (); url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz + "#wechat_redirect"; // divide la dirección de url de mensajes históricos de cuenta oficial (el formulario de la segunda página) // Actualiza el campo de tiempo de recopilación en la tabla de cuentas oficial mencionada ahora a la campaña actual de la cuenta. weixin.setCollect (System.CurrentTimemillis ()); int resultado = weixinmapper.updateByPrimaryKey (weixin); System.out.println ("Gethis weixin Updateresult:"+resultado); } else {// Obtener el campo content_url de la línea actual url = queue.getContentUrl (); // Actualizar el campo de carga a 1 tmplistMapper.UpdateByContentUrl (URL); } // Cambie el siguiente $ URL para ser redirigido a un script JS e inyectarlo en la página de WeChat por 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>"; return jscode; }Lo anterior es el programa que procesa los datos interceptados por el servidor proxy. Hay un problema al que debe prestarse atención aquí. El programa llevará a cabo acceso a la redonda a cada cuenta oficial incluida en la base de datos, e incluso se accederá nuevamente a los artículos almacenados. El propósito es seguir actualizando el número de puntos de vista y me gusta del artículo. Si necesita rastrear una gran cantidad de cuentas públicas, se recomienda modificar el código para agregar colas de tareas y agregar restricciones condicionales. De lo contrario, la cuenta oficial rastreará datos duplicados en múltiples rondas y los ciclos afectará en gran medida la eficiencia.
En este punto, todos los enlaces del artículo de la cuenta oficial de WeChat se rastrearon, y este enlace es permanentemente válido y se puede abrir en el navegador. A continuación, escriba un programa de rastreadores para rastrear el contenido del artículo y otra información de la base de datos.
Soy un rastreador escrito en WebMagic, es liviano y fácil de usar.
Public Class Spidermodel implementa PageProcessor {Postmapper Postmapper estático privado; Lista estática privada <Post> publicaciones; // Configuración relevante del sitio web de Crawl, que incluye codificación, intervalo de rastreo, tiempos de reintento, etc. Sitio privado Site = Site.me (). SetretryTimes (3) .SetSleepTime (100); Sitio público getSite () {// TODO Auto Generado Método STUB return this.site; } Public void Process (página de página) {// TODO Auto Generado Método STUB Post = Posts.Remove (0); String content = page.gethtml (). Xpath ("// div [@id = 'js_content']"). Get (); // Los artículos de Harry se determinan aquí. Si hay un registro de eliminación directa o establece el bit de representación para indicar que el artículo es armonioso si (content == null) {System.out.println ("¡El artículo es armonioso!"); //postmapper.deleteByPrimaryKey (post.getID ()); devolver; } String contentsNap = content.replaceAll ("data-src", "src"). Replaceall ("previsor.html", "jugador.html"); // snapshot string contentTxt = htmltoword.striphtml (contenido); // texto de texto con contenido de contenido de contenido = metacontent = metacontent = Metacontent = page.gethtml (). Xpath ("// div [@id = 'meta_content']"); String PubTime = null; Cadena wxname = null; Cadena autor = nulo; if (metacontent! = null) {pubTime = metacontent.xpath ("// em [@id = 'post-fate']"). get (); if (PUBTime! = NULL) {PUBTIME = HTMLTOWORD.STRIPHTML (PUBTIME); // Tiempo de publicación de artículo} wxname = metacontent.xpath ("// a [@id = 'post-user']"). get (); if (wxname! = null) {wxname = htmltoword.striphtml (wxname); // nombre de cuenta pública} autor = metacontent.xpath ("// em [ @class = 'rich_media_meta_media_meta_text' y @id! = 'post-date']"). get ();;; if (autor! = null) {autor = htmltoword.striphtml (autor); // Artículo Autor}} // System.out.println ("Publicar Time:"+PubTime); // System.out.println ("Nombre de la cuenta pública:"+WXName); // System.Println ("Artículo Autor:"+Autor); Title de cadena = post.gettitle (). ReplaceAll ("", ""); // Artículo Title String Digest = Post.getDigest (); // Artículo sumario int LeaTenum = Post.getLikenum ();/El artículo me gusta int readnum = post.getReadnum (); // Artículo Lecturas String String ContentUrl =getContentUrl (); // Artículo de artículo WeChatinfobean. WeChatinfobean (); Wechatbean.Settitle (título); wechatBean.setContent (contentTxt); // Contenido de texto sin formato wechatBean.setSourCecode (contentsnap); // snapshot wechatbean.setLikecount (lateNum); wechatbean.setViewCount (readNum); wechatbean.setabstractText (digest); // abstract wechatbean.seturl (contentUrl); wechatbean.setPublishTime (PubTime); wechatbean.setsitename (wxname); // nombre del sitio cuenta de cuenta pública name wechatbean.setAuthor (autor); wechatBean.setMediatype ("Cuenta oficial de WeChat"); // Tipo de medios de origen WeChatStorage.SaveWeChatinfo (WeChatBean); // Etiqueta El artículo se ha rastreado después. Postmapper.UpdateByPrimaryKey (post); } public static void startspider (List <St> InPosts, Postmapper MyPostMapper, String ... URLS) {Long Starttime, EndTime; starttime = system.currentTimemillis (); postmapper = myPostMapper; Post = InPosts; HttpClientDownloader httpClientDownloader = new httpClientDownloader (); Spidermodel spidermodel = new Spidermodel (); Spider myspider = spider.create (spidermodel) .addurl (urls); mySpider.SetDownLoader (httpClientDownloader); intente {spidermonitor.instance (). registrar (myspider); myspider.thread (1) .run (); } catch (JMexception e) {E.PrintStackTrace (); } EndTime = System.CurrentTimemillis (); System.out.println ("Tiempo de rastreo" + ((EndTime-Starttime) / 1000) + "Segundos--"); }}No publicaré otros códigos de almacenamiento lógico irrelevantes. Aquí puse los datos capturados por el servidor proxy en MySQL y almacené los datos arrastrados por mi programa de rastreadores en MongoDB.
A continuación se muestra la información sobre el número de cuenta oficial que se arrastró: