Recentemente, preciso rastejar as informações do artigo da conta oficial do WeChat. Eu procurei on -line e descobri que a dificuldade de rastejar contas públicas do WeChat é que o link para o artigo da conta oficial não pode ser aberto no lado do PC. Devemos usar o próprio navegador do WeChat (você só pode abri -lo em outras plataformas depois de obter os parâmetros complementados pelo cliente WeChat). Isso causa um grande problema ao programa de rastreador. Mais tarde, vi um programa de rastejamento oficial do WeChat, escrito por um grande cara em Zhihu, e segui diretamente a idéia do chefe e a transformei em Java. Encontrei muitos problemas detalhados durante a transformação, então vou compartilhá -la.
A idéia básica do sistema é executar o WeChat no emulador Android, configurar um proxy para o emulador, interceptar dados do WeChat através do servidor proxy e enviar os dados obtidos ao seu próprio programa para processamento.
Ambientes que precisam ser preparados: Nodejs, Proxy de Anyproxy e Emulador Android
Endereço de download do NodeJS: http://nodejs.cn/download/. Eu baixei a versão do Windows, basta instalá -la diretamente. Após a instalação, a execução de arquivos c:/programs/nodejs/npm.cmd configurará automaticamente o ambiente.
Instalação de AnyProxy: Depois de instalar o NodeJS de acordo com a etapa anterior, execute o NPM Install -g AnyProxy diretamente no CMD e instale
Basta ir ao emulador Android on -line, muitos deles.
Primeiro, instale o certificado para o servidor proxy. AnyProxy não resolve o link HTTPS por padrão. Depois de instalar o certificado, ele pode ser resolvido. Execute AnyProxy -Root em CMD para instalar o certificado. Depois disso, você deve baixar este certificado no emulador.
Em seguida, digite qualquer comando de qualquer protoxy -i para abrir o serviço de proxy. (Lembre -se de adicionar parâmetros!)
Lembre -se deste IP e da porta, e o agente do emulador Android usará isso. Agora use seu navegador para abrir a página da web: http: // localhost: 8002/Esta é a interface da web de qualquer protoxy, usada para exibir dados de transmissão HTTP.
Clique no menu na caixa vermelha acima e um código QR será lançado. Use o emulador Android para digitalizar o código para identificá -lo. O emulador (telefone celular) baixará o certificado e apenas o instalará.
Agora você está pronto para configurar um proxy para o emulador. O método proxy está definido como manual. O IP proxy é o IP que executa qualquer máquina de proproxy e a porta é 8001
O trabalho de preparação é basicamente concluído aqui. Abra o WeChat no emulador e abra um artigo em uma conta pública, e você pode ver os dados capturados por qualquer protoxy na interface da web que você acabou de abrir:
O link para o artigo do WeChat está na caixa vermelha acima. Clique para ver os dados específicos. Se não houver nada no corpo da resposta, há um problema com a instalação do certificado.
Se tudo o exposto estiver pronto, você pode continuar a descer.
Aqui, contamos com serviços de proxy para capturar dados do WeChat, mas não podemos pegar uma peça de dados e operar o WeChat por nós mesmos. É melhor copiá -lo manualmente. Portanto, precisamos que o cliente do WeChat pule para a página por si só. No momento, você pode usar qualquer protoxy para interceptar os dados retornados pelo servidor WeChat, injetar o código de salto de página nele e, em seguida, retorne os dados processados ao simulador para obter um salto automático do cliente WeChat.
Abra um arquivo JS chamado regra_default.js em AnyProxy. O arquivo no Windows é: c:/usuários/administrador/appdata/roaming/npm/node_modules/anyproxy/lib
Existe um método chamado SubstituaServerResDataasync: function (req, res, serverResdata, retorno de chamada) no arquivo. Este método é responsável por executar várias operações nos dados obtidos por qualquer protoxi. No início, deve haver apenas retorno de chamada (serverResdata); Esta declaração significa retornar diretamente os dados de resposta ao servidor ao cliente. Exclua esta declaração diretamente e substitua -a pelo código a seguir escrito por Daniu. Não fiz nenhuma alteração no código aqui, e os comentários são explicados com muita clareza. Basta lê -los diretamente de acordo com a lógica, e não há grande problema.
SubstituaServerResDataasync: function (req, res, serverResdata, retorno de chamada) {if (/mp//getmassendmsg/i.test (req.url)) {// Quando o endereço do link é a página histórica da conta (primeira página) //console.log(start the First Page ry rir a Página Primeira Página; if (serverResdata.toString ()! == "") {6 tente {// impedem que os erros saem do programa var reg =/msglist = (. Httppost (ret [1], req.url, "/internetspider/getData/showbiz"); // Esta função é definida posteriormente, enviando a mensagem histórica correspondente a seu próprio servidor var http = requer ('http'); http.get ('http: // xxx/getwxhis', function (res) {// Este endereço é um programa em seu próprio servidor. O objetivo é obter o próximo endereço de link, colocar o endereço em um script JS e pular automaticamente para a próxima página. Retorno de chamada (Chunk+ServerResdata); // Insira o código retornado na página de mensagem histórica e retorne para exibi -lo})}); } catch (e) {// Se o regular não corresponder, o conteúdo desta página pode ser a segunda página da página de mensagem histórica da conta oficial, porque a primeira página da mensagem histórica está no formato HTML e a segunda página está no formato JSON. //console.log("start the First Page Rast para baixo da forma "); tente {var json = json.parse (serverResdata.toString ()); if (json.general_msg_list! = []) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); // Esta função é definida posteriormente como acima, enviando o json da segunda mensagem histórica para o seu próprio servidor (e}} (e) {console.nson. retorno de chamada (serverResdata); // retorna diretamente para a segunda página JSON Content}} //console.log("start the First Page Crawl End "); } else if (/mp//profile_ext/?action=home/i.test (req.url)) {// Quando o endereço do link é a página de mensagem histórica da conta oficial (o formulário da segunda página) tente {var reg =/var msGlist = /'(.*? Reg.exec (ServerResdata.toString ()); // converte a variável para string httppost (ret [1], req.url, "/xxx/showbiz"); // Esta função é definida posteriormente, envie a mensagem histórica correspondente ao seu próprio servidor var http = request ('http'); http.get ('xxx/getwxhis', function (res) {// Este endereço é um programa no seu servidor. O objetivo é obter o próximo endereço de link, colocar o endereço em um script js e pular automaticamente para a próxima página. Código retornado na página de mensagem histórica e retorne para exibi -lo})}); } catch (e) {//console.log(e); retorno de chamada (serverResdata); }} else if (/mp//profile_ext/?action=getmsg/i.test (req.url)) {// a expressão da segunda página json try {var json = json.parse (serverResdata.toString ()); if (json.general_msg_list! = []) {httppost (json.general_msg_list, req.url, "/xxx/showbiz"); // Esta função é definida posteriormente como acima, enviando o json da segunda página histórica para seu próprio servidor (et; } retorno de chamada (serverResdata); } else if (/mp//getAppmsgext/i.test (req.url)) {// Quando o endereço do link é o número de visualizações e curtidas para o artigo da conta oficial, tente {httppost (serverresdata, req.url, "/xxx/getMsgext"); // a função é servidor} catch (e) {} retorno de chamada (serverResdata); } else if (/s/? __ biz/i.test (req.url) || /mp//rumor/i.test(req.url))) {/wwhen O endereço do link é o artigo da conta oficial (o endereço do rumor é o artigo da conta oficial, foi negado) tentativa {var http = request ('http'; http.get ('http: // xxx/getwxpost', function (res) {// Este endereço é outro programa no seu servidor. O objetivo é obter o próximo endereço de link, colocar o endereço em um script JS e pular automaticamente para a próxima página. retorno de chamada (Chunk+ServerResdata); } catch (e) {retorno de chamada (serverResdata); }} else {retorno de chamada (serverResdata); } // retorno de chamada (serverResdata); },Deixe -me explicar brevemente aqui que existem duas formas de links para a página de mensagens históricas das contas oficiais do WeChat: uma começa com MP.Weixin.qq.com/mp/getmassendmsg e o outro começa com mp.weixin.qq.com/mp/profile_ext. A página de história pode ser invertida. Se desativado, ele acionará o evento JS para enviar uma solicitação para obter dados JSON (o conteúdo da próxima página). Também existem links oficiais do artigo de conta, bem como links para o número de artigos lidos e curtidas (retornando dados JSON). Os formulários desses links são fixos e podem ser distinguidos pelo julgamento lógico. Há uma pergunta aqui: como fazer se todas as páginas de história precisam ser rastejadas. Minha idéia é simular o mouse deslizando através do JS, desencadeando assim a solicitação para enviar uma solicitação para carregar a próxima parte da lista. Ou use diretamente AnyProxy para analisar a solicitação de carregamento deslizante e gerar diretamente essa solicitação para o servidor WeChat. Mas há um problema em como julgar que não há dados restantes. Estou rastejando os dados mais recentes e não tenho esse requisito por enquanto, e posso querer no futuro. Se você precisar, você pode tentar.
A figura a seguir é o conteúdo do método HTTPPOST acima.
função httppost (str, url, path) {// Envie JSON para o servidor, o STR é o conteúdo JSON, o URL é o endereço da página de mensagem histórica, o caminho é o caminho e o nome do arquivo do programa de recebimento
console.log ("Comece a encaminhar");
tentar{
var http = requer ('http');
var dados = {
STR: Encodeuricomponent (STR),
URL: Encodeuricomponent (URL)
};
dados = requer ('Querystring'). stringify (dados);
var options = {
Método: "post",
Host: "xxx", // Observe que não há http: //, este é o nome de domínio do servidor.
Porta: xxx,
Caminho: Caminho, // O caminho e o nome do arquivo do programa de recebimento
Cabeçalhos: {
'Content-Type': 'Application/X-Www-Form-Urlencoded; charset = utf-8 ',
"Length-thength": data.length
}
};
var req = http.request (opções, função (res) {
res.setEncoding ('utf8');
res.on ('dados', função (chunk) {
console.log ('corpo:' + pedaço);
});
});
req.on ('erro', função (e) {
console.log ('problema com a solicitação:' + e.message);
});
req.write (dados);
req.end ();
} catch (e) {
console.log ("mensagem de erro:"+e);
}
console.log ("Operação de encaminhamento termina");
}Depois de fazer o trabalho acima, a próxima etapa é concluir o código do servidor de acordo com seu próprio negócio. Nosso serviço é usado para receber dados enviados pelo servidor proxy para processamento, executar operações persistentes e, ao mesmo tempo, envie o código JS que precisa ser injetado no WeChat para o servidor proxy. Para dados enviados de vários links diferentes interceptados pelo servidor proxy, precisamos projetar métodos correspondentes para processar esses dados. Do método JS de qualquer protoxy de processamento de dados do WeChat, substituindo os dados do REVESDATRESSYNC: function (req, res, ServerResdata, retorno de chamada), podemos saber que pelo menos três métodos são necessários para projetar os dados oficiais da página do histórico de contas, dados oficiais da página da conta, dados da conta oficial como artigo e dados de leitura. Ao mesmo tempo, também precisamos projetar um método para gerar tarefas de rastreamento e concluir a viagem de ida e volta da conta oficial. Se você precisar rastrear mais dados, poderá analisar os dados mais necessários dos links capturados por qualquer protoxi e, em seguida, adicionar um julgamento para substituir o SubstituirVerResDataasync: function (req, res, ServerResData, chamada de retorno), interceptar os dados necessários e enviá -los ao seu próprio servidor e adicionar o método correspondente a processar esse tipo de dados sobre os dados.
Estou escrevendo código do servidor em java.
Métodos para processar dados da página de histórico de contas oficiais:
public void getMsgjson (String str, String URL) lança UnsupportEdEncodingException {// TODO Método Gerado Auto-Generado Stub String Biz = ""; Mapa <string, string> Querystrs = httpurlparser.parseurl (url); if (Querystrs! = null) {Biz = Querystrs.get ("__ Biz"); biz = biz + "=="; } /*** Consulta do banco de dados Se o Biz já existe e insira -o se não existir. * Isso significa que adicionamos uma nova conta oficial para a meta de cobrança. */ List <weixin> resultados = 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); // Lista de variáveis de análise STR <BONED> LISTS = JSONPATH.READ (STR, "['LIST']"); para (Lista de objetos: listas) {objeto json = list; int tipo = jsonpath.read (json, "['comm_msg_info'] ['type']"); if (type == 49) {// type = 49 significa que é uma mensagem de texto string content_url = jsonpath.read (json, "$ .app_msg_ext_info.content_url"); content_url = content_url.replace ("//", "") .replaceall ("amp;", ""); // obtenha o endereço de link da mensagem de texto int is_multi = jsonpath.read (json, "$ .app_msg_ext_info.is_multi"); // é um multi -fl. "$ .comm_msg_info.dateTime"); // envia tempo de imagem e mensagem de texto/** * Aqui a imagem e o endereço do link da mensagem de texto é inserido na biblioteca da fila de aquisição tmplist * (a biblioteca da fila) será introduzida posteriormente. if (content_url! = null &&! "". Equals (content_url)) {tmplist tmplist = new tmplist (); tmplist.setContenturl (content_url); tmplistmapper.insertSelective (tmplist); }} catch (Exceção e) {System.out.println ("A fila já existe, não inserida!"); } / *** Aqui julgamos se é repetido na postagem do banco de dados com base em $ content_url* / list <Post> postList = postmapper.selectByContenturl (content_url); contenturlexista booleano = false; if (postList! = null && postList.size ()! = 0) {contenturlexist = true; } if (! Contenturlexist) {// 'O mesmo $ content_url existe no banco de dados Post' Integer FileId = jsonPath.read (json, "$ .app_msg_ext_info.fileid"); // a wechat id string = jsonph.read. (JSON), ".pApp_MSG_MSG_FAT_FORTSG_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FETT_FEXTA); Urlencoder.encode (título, "UTF-8"); String Digest = jsonPath.read (json, "$ .app_msg_ext_info.digest"); // resumo do artigo String fonte_url = jsonPath.read (json, "$ .app_msg_ext_info.source_url"); // leia o texto original (fonte de origem = fonte; String cover = jsonpath.read (json, "$ .app_msg_ext_info.cover"); // cover capa = cover.replace ("//", ""); /*** Salvar no banco de dados* /// System.out.println ("Title:"+title); // System.out.println ("WeChat ID:"+fileId); // System.out.println ("resumo do artigo:"+diger); // System.out.println ("read Link:" endereço: "+capa); Post post = novo post (); post.setBiz (Biz); post.setTitle (título); post.setTitleEncode (title_encode); post.setFieldId (FileId); post.setDigest (Digest); post.SetSourceUrl (fonte_URL); post.setCover (capa); post.setistop (1); // etiqueta -o como o título de conteúdo post.setismulti (is_multi); post.setDateTime (DateTime); post.setContenturl (content_url); postmapper.insert (post); } if (is_multi == 1) {// se for uma lista de mensagens multi-gráficas <Puject> multilistas = jsonpath.read (json, "['app_msg_ext_info'] ['multi_app_msg_item_list']"); para (Multilista de objeto: multilistas) {objeto multijson = multilista; content_url = jsonPath.read (multijson, "['content_url']"). LIST <SOST> POST = POSTMAPPER.SELECTBYCONTENTURL (CONTENT_URL); if (posts! = null && posts.size ()! = 0) {contenturlexist = true; } if (! contenturlexist) {// 'O mesmo $ content_url não está presente no banco de dados'/** * aqui, insira o endereço de link de mensagem gráfico e de texto na biblioteca da fila de aquisição * (a biblioteca da fila) será apresentada posteriormente. null &&! "". Equals (content_url)) {tmplist tmplistt = new tmplist (); tmplistt.setContenturl (content_url); tmplistmapper.insertSelective (tmplistt); } String title = jsonpath.read (multijson, "$ .title"); String title_encode = urlencoder.encode (title, "utf-8"); Inteiro fileid = jsonPath.read (multijson, "$ .fileId"); String Digest = jsonPath.read (multijson, "$ .digest"); String source_url = jsonpath.read (multijson, "$ .source_url"); fonte_url = fonte_url.replace ("//", ""); Capa de string = jsonPath.read (multijson, "$ .cover"); cover = cover.replace ("//", ""); // System.out.println ("Title:"+title); // System.out.println ("WeChat ID:"+FILEID); // System.out.println ("Resumo do artigo:"+Digest); // System.out.println ("Read Original Link:" OROTEL); Post post = novo post (); post.setBiz (Biz); post.setTitle (título); post.setTitleEncode (title_encode); post.setFieldId (FileId); post.setDigest (Digest); post.SetSourceUrl (fonte_URL); post.setCover (capa); post.setistop (0); // tag Não é o manchete de conteúdo post.setismulti (is_multi); post.setDateTime (DateTime); post.setContenturl (content_url); postmapper.insert (post); }}}}}}}}}Como lidar com as páginas oficiais do artigo de conta:
public String getwxPost () {// TODO Método Gerado automaticamente Stub / *** Quando a página atual é a página do artigo da conta oficial, leia este programa* primeiro exclua o carregamento da linha = 1 na lista de filas de coleta* depois selecione várias linhas de acordo com "Order by Id ASC" da fila (observe que esta linha é diferente do programa 1)* / tmplists. Lista <TMPlist> filas = tmplistmapper.SelectMany (5); String url = ""; if (filas! = null && fileues.size ()! = 0 && fileues.size ()> 1) {tmplist fileue = fileues.get (0); url = fileue.getContenturl (); fila.setisload (1); int resultado = tmplistmapper.UpDateByPrimaryKey (fila); System.out.println ("resultado da atualização:"+resultado); } else {System.out.println ("Filas getPost é null?"+filas == null? null: fileues.size ()); Weixin weixin = weixinMapper.SelectOne (); String biz = weixin.getbiz (); if ((math.random ()> 0,5? 1: 0) == 1) {url = "http://mp.weixin.qq.com/mp/getmassendmsg?__biz=" + biz + "#wechat_webview_type = 1 & wechat_redirect"; url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz + "#wechat_redirect"; // dividiu o endereço da URL da mensagem oficial da conta oficial (segunda página da página)} Url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz + "#wechat_redirect"; // dividiu o endereço da URL da conta oficial da conta do selo histórico (o segundo formulário de página) // Atualize o campo de tempo de coleta na tabela oficial mencionada agora para o selo no momento da tabela de tempo. weixin.setCollect (System.CurrentTimEmillis ()); int resultado = weixinMapper.UpDateByPrimaryKey (Weixin); System.out.println ("getPost weixin updateResult:"+resultado); } int RandomTime = new Random (). NextInt (3) + 3; String jscode = "<Script> setTimeout (function () {Window.Location.href = '"+url+"';},"+RandomTime*1000+"); </script>"; retornar jscode; }Como lidar com o número de curtidas e leituras de contas oficiais:
public void getMsgext (string str, string url) {// TODO Method Auto-Generated Stub String biz = ""; String sn = ""; Mapa <string, string> Querystrs = httpurlparser.parseurl (url); if (Querystrs! = null) {Biz = Querystrs.get ("__ Biz"); biz = biz + "=="; sn = querystrs.get ("sn"); sn = "%" + sn + "%"; } /** * $ sql = "Selecione * da tabela de artigos onde` Biz` = '". $ biz."' * e `content_url` like '%". * Encontre o artigo correspondente baseado em Biz e Sn*/ Post Post = PostMapper.SelectByBizandsn (Biz, Sn); if (post == null) {System.out.println ("Biz:"+Biz); System.out.println ("sn:"+sn); tmplistmapper.deletebyload (1); retornar; } // System.out.println ("JSON Data:"+str); Inteiro read_num; Número inteiro como_num; tente {read_num = jsonpath.read (str, "['appmsgstat'] ['read_num']"); // leia o volume like_num = jsonpath.read (str, "['appmsgstat'] ['como_num']"); // como o volume} (excepção e) {read_num_num = 123; System.out.println ("read_num:"+read_num); System.out.println ("like_num:"+like_num); System.out.println (e.getMessage ()); } /*** Aqui, o artigo correspondente também é excluído na lista de filas de coleção com base no SN, o que significa que este artigo pode ser removido da fila de coleções. * $ sql = "Exclua da` listagem da equipe 'onde `content_url` like'%". $ sn. "%'" */ tmplistmapper.deleteBysn (sn); // Atualize o número de visualizações e gosta da tabela de artigos. post.SetReadNum (read_num); post.setlikenum (like_num); postmapper.UpDateByPrimaryKey (POST); }Como lidar com o salto para a injeção de WeChat JS:
public string getwxhis () {string url = ""; // TODO Método generalizado automaticamente stub /*** Quando a página atual é uma mensagem histórica da conta pública, leia este programa* Existe um campo de carga na lista de filas de coleção. Quando o valor for igual a 1, significa que está sendo lido* primeiro exclua a linha de carga = 1 na lista de filas de coleta* e selecione qualquer linha na lista de equipes*/ tmplistmapper.deletebyload (1); Fila tmplist = tmplistmapper.SelectrandOMONE (); System.out.println ("fila é nulo?"+Fila); if (fila == null) {// A lista de filas estiver vazia/*** Se a lista de filas estiver vazia, obtenha um negócio da tabela que armazena o negócio oficial da conta. * Aqui eu defino um campo de tempo do tempo de coleta na tabela de conta oficial. Depois de classificá -lo em ordem positiva, * obtenha o registro da conta oficial com o menor carimbo de hora e obtenha seus negócios */ weixin weixin = weixinMapper.selectone (); String biz = weixin.getbiz (); url = "https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=" + biz + "#wechat_redirect";//Split the official account historical message url address (the second page form) //Update the collection time time field in the official account table mentioned just now to the current timestamp. weixin.setCollect (System.CurrentTimEmillis ()); int resultado = weixinMapper.UpDateByPrimaryKey (Weixin); System.out.println ("Gethis weixin updateResult:"+resultado); } else {// Obtenha o campo Content_URL da linha atual url = fileue.getContenturl (); // Atualize o campo Carregar para 1 tmplistmapper.UpDateByContenturl (URL); } // Altere o próximo $ url a ser redirecionado para um script JS e injete -o na página do WeChat por AnyProxy. // echo "<cript> 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>"; retornar jscode; }O exposto acima é o programa que processa os dados interceptados pelo servidor proxy. Há um problema que precisa receber atenção aqui. O programa realizará acesso redondo-robin a cada conta oficial incluída no banco de dados, e até os artigos armazenados serão acessados novamente. O objetivo é continuar atualizando o número de visualizações e curtidas no artigo. Se você precisar rastejar um grande número de contas públicas, é recomendável modificar o código para adicionar filas de tarefas e adicionar restrições condicionais. Caso contrário, a conta oficial rastejará dados duplicados em várias rodadas e ciclos afetará bastante a eficiência.
Nesse ponto, todos os links do artigo da conta oficial do WeChat foram rastejados, e esse link é permanentemente válido e pode ser aberto no navegador. Em seguida, escreva um programa de rastreador para rastrear o conteúdo do artigo e outras informações do banco de dados.
Eu sou um rastreador escrito em webmagic, é leve e fácil de usar.
classe pública Spidermodel implementa PageProcessor {private Static Postmapper Postmapper; Lista estática privada <Sost> postagens; // Configuração relevante do site CRAWL, incluindo codificação, intervalo de rastreamento, horários de tentativa, etc. site privado site = site.me (). SetretryTimes (3) .SetSleePtime (100); Public Site getSite () {// TODO Método Gerado de Auto-Goletes Retornar este.site; } Processo public void (página da página) {// TODO Método Auto-Gerado Stub Post Post = Posts.remove (0); String Content = Page.gethtml (). Xpath ("// div [@id = 'js_content']"). Get (); // Os artigos de Harry são determinados aqui. Se houver um registro de exclusão direta ou definir o bit de representação para indicar que o artigo é harmonioso se (content == null) {System.out.println ("O artigo é harmonioso!"); //postmapper.deletebyPrimaryKey (post.getId ()); retornar; } String contentsnap = Content.ReplaceAll ("Data-src", "src"). ReplaceAll ("visualize.html", "player.html"); // snapshot string contenttxt = htmltoword.striphtml (conteúdo) // conteúdo de texto simples página.gethtml (). Xpath ("// div [@id = 'meta_content']"); String PubTime = NULL; String wxname = null; String Author = null; if (metacontent! = null) {pubtime = metacontent.xpath ("// em [@id = 'pós-data']"). get (); if (pubTime! = null) {pubTime = htmltoword.striphtml (pubtime); // time de publicação de artigo} wxname = metacontent.xpath ("// a [@id = 'pós-user']"). get (); if (wxname! = null) {wxname = htmltoword.striphtml (wxname); // nome da conta pública} autor = metacontent.xpath ("// [ @class = 'rich_media_meta rich_media_meta_text' e @id! if (autor! = null) {autor = htmltoword.striphtml (autor); // autor do artigo}} // System.out.println ("publicar tempo:"+pubtime); // System.out.println ("Public Name:"+WxName); String title = post.gettitle (). Replaceall ("", ""); // título do artigo String string diger = post.getDigest (); // resumo do artigo int likenum = post.getlikenum (); // artigos de wechats de readnum = post.getReadNum (); // Artigo String Stringnturl =.CenturlTurntur = Post.getReadNum (); novo wechatinfobean (); weChatbean.settitle (título); wechatbean.setContent (contentTxt); // conteúdo de texto simples wechatbean.setsourcecode (contentsnap); // snapshot weChatbean.setlikecount (gaipanum); wechatbean.setViewCount (readnum); weChatbean.setabstractText (Digest); // abstract weChatbean.seturl (contenturl); WeChatbean.setPublishtime (PubTime); WeChatbean.SetSITENAME (WXNAME); // Nome do site Nome da conta public weChatbean.SetAuthor (autor); weChatbean.setMediaType ("Conta Oficial do WeChat"); // tipo de mídia de origem wechatstorage.savewechatinfo (Wechatbean); // tag o artigo foi rastejado post.setisspider (1); postmapper.UpDateByPrimaryKey (POST); } public static void startSpider (list <sic> inposts, pós -mapper myPostmapper, string ... urls) {long starttime, EndTime; startTime = system.currenttimemillis (); postmapper = myPostmapper; Postagens = INSPOSTS; HttpClientDownloader httpClientDownloader = new HttpClientDownloader (); Spidermodel Spidermodel = new Spidermodel (); Aranha myspider = spider.create (spidermodel) .addurl (urls); myspider.setDownloader (httpclientDownloader); tente {spidermonitor.Instance (). Register (mySpider); mySpider.Thread (1) .run (); } catch (jMexception e) {e.printStackTrace (); } endtime = System.currenttimemillis (); System.out.println ("tempo de rastreamento" + ((ENDTime-starttime) / 1000) + "segundos--"); }}Não vou postar outros códigos de armazenamento lógicos irrelevantes. Aqui, coloquei os dados capturados pelo servidor proxy no MySQL e armazenei os dados rastejados pelo meu programa de rastreador em MongoDB.
Abaixo está as informações sobre o número da conta oficial que você rastejou: