Maison  >  Article  >  interface Web  >  Node utilise Puppeteer comme robot d'exploration

Node utilise Puppeteer comme robot d'exploration

php中世界最好的语言
php中世界最好的语言original
2018-06-07 14:06:002577parcourir

Cette fois, je vais vous présenter l'utilisation de Puppeteer par Node en tant que robot d'exploration. Quelles sont les précautions à prendre pour l'utilisation de Puppeteer en tant que robot d'exploration par Node. Ce qui suit est un cas pratique, jetons un coup d'œil.

Schéma d'architecture

Schéma d'architecture de Marionnettiste

  1. Puppeteer communique avec le navigateur via devTools

  2. Navigateur Une instance de navigateur (chroium) qui peut avoir plusieurs pages

  3. Page Une page qui contient au moins un cadre

  4. Frame dispose d'au moins un environnement d'exécution pour exécuter javascript et peut également étendre plusieurs environnements d'exécution

Avant-propos

Je souhaite l'acheter récemment Un ordinateur de bureau et un ordinateur portable i5 ont des retards évidents lors de l'ouverture des pages Web et du vsc, je prévois donc d'utiliser un ordinateur i7 + GTX1070TI ou GTX1080TI. La recherche directement sur Taobao nécessite de tourner trop de pages et il y a trop d'images. Je ne peux pas le supporter, je souhaite donc explorer certaines données et utiliser des graphiques pour analyser les tendances récentes des prix. Par conséquent, j'ai écrit un robot utilisant Puppeteer pour explorer les données pertinentes.

Qu'est-ce que Marionnettiste ?

Puppeteer est une bibliothèque de nœuds qui fournit une API de haut niveau pour contrôler Chrome ou Chromium sans tête via le protocole DevTools. Elle peut également être configurée pour utiliser Chrome ou Chromium complet (non sans tête).

En bref, ce produit est une bibliothèque de nœuds qui fournit une API de haut niveau. Il peut contrôler le chrome ou le chrome en mode sans tête via devtool. Il peut simuler n'importe quelle opération humaine en mode sans tête.

La différence entre cheerio et cheerio

cherrico est essentiellement simplement une bibliothèque qui utilise une syntaxe de type jquery pour manipuler des documents HTML. L'utilisation de cherrico pour explorer les données ne demande que du HTML statique. . Document, si les données contenues dans la page Web sont obtenues dynamiquement via ajax, les données correspondantes ne peuvent pas être explorées. Puppeteer peut simuler l'environnement d'exploitation d'un navigateur, demander des informations sur un site Web et exécuter la logique interne du site Web. Ensuite, il obtient dynamiquement les données à l'intérieur de la page via le protocole WS, peut effectuer toutes les opérations simulées (clic, glisser, survoler, etc.) et prend en charge les sauts de page et la gestion multi-pages. Il peut même injecter des scripts sur le nœud dans l'environnement interne du navigateur pour les exécuter. En bref, il peut faire tout ce que vous pouvez faire sur une page Web, et il peut également faire des choses que vous ne pouvez pas faire.

Démarrer

Cet article n'est pas un tutoriel étape par étape, vous devez donc avoir des connaissances de base sur l'API Puppeteer. Si vous ne comprenez pas, veuillez. lisez d'abord l'introduction officielle
Site officiel de Puppeteer
PuppeteerAPI

Nous observons d'abord les informations du site Web que nous voulons explorer GTX1080

C'est la page Taobao que nous voulons explorer uniquement. Les éléments du produit au milieu sont le contenu que nous devons explorer. Après avoir soigneusement analysé sa structure, je pense que chaque frontal a de telles capacités.

Le Typescript que j'utilise peut obtenir des conseils API complets pour Puppetter et les bibliothèques associées. Si vous ne connaissez pas TS, il vous suffit de modifier le code correspondant en syntaxe ES

// 引入一些需要用到的库以及一些声明
import * as puppeteer from 'puppeteer' // 引入Puppeteer
import mongo from '../lib/mongoDb' // 需要用到的 mongodb库,用来存取爬取的数据
import chalk from 'chalk' // 一个美化 console 输出的库
const log = console.log // 缩写 console.log
const TOTAL_PAGE = 50 // 定义需要爬取的网页数量,对应页面下部的跳转链接
// 定义要爬去的数据结构
interface IWriteData { 
 link: string // 爬取到的商品详情链接
 picture: string // 爬取到的图片链接
 price: number // 价格,number类型,需要从爬取下来的数据进行转型
 title: string // 爬取到的商品标题
}
// 格式化的进度输出 用来显示当前爬取的进度
function formatProgress (current: number): string { 
 let percent = (current / TOTAL_PAGE) * 100
 let done = ~~(current / TOTAL_PAGE * 40)
 let left = 40 - done
 let str = `当前进度:[${''.padStart(done, '=')}${''.padStart(left, '-')}]  ${percent}%`
 return str
}

Suivant. nous commençons à entrer dans la logique principale du robot

// 因为我们需要用到大量的 await 语句,因此在外层包裹一个 async function
async function main() {
 // Do something
}
main()
// 进入代码的主逻辑
async function main() {
 // 首先通过Puppeteer启动一个浏览器环境
 const browser = await puppeteer.launch()
 log(chalk.green('服务正常启动'))
 // 使用 try catch 捕获异步中的错误进行统一的错误处理
 try {
  // 打开一个新的页面
  const page = await browser.newPage()
  // 监听页面内部的console消息
  page.on('console', msg => {
   if (typeof msg === 'object') {
    console.dir(msg)
   } else {
    log(chalk.blue(msg))
   }
  })
  // 打开我们刚刚看见的淘宝页面
  await page.goto('https://s.taobao.com/search?q=gtx1080&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20180416&ie=utf8')
  log(chalk.yellow('页面初次加载完毕'))
  // 使用一个 for await 循环,不能一个时间打开多个网络请求,这样容易因为内存过大而挂掉
  for (let i = 1; i <= TOTAL_PAGE; i++) {
   // 找到分页的输入框以及跳转按钮
   const pageInput = await page.$(`.J_Input[type=&#39;number&#39;]`)
   const submit = await page.$(&#39;.J_Submit&#39;)
   // 模拟输入要跳转的页数
   await pageInput.type(&#39;&#39; + i)
   // 模拟点击跳转
   await submit.click()
   // 等待页面加载完毕,这里设置的是固定的时间间隔,之前使用过page.waitForNavigation(),但是因为等待的时间过久导致报错(Puppeteer默认的请求超时是30s,可以修改),因为这个页面总有一些不需要的资源要加载,而我的网络最近日了狗,会导致超时,因此我设定等待2.5s就够了
   await page.waitFor(2500)
   // 清除当前的控制台信息
   console.clear()
   // 打印当前的爬取进度
   log(chalk.yellow(formatProgress(i)))
   log(chalk.yellow(&#39;页面数据加载完毕&#39;))
   // 处理数据,这个函数的实现在下面
   await handleData()
   // 一个页面爬取完毕以后稍微歇歇,不然太快淘宝会把你当成机器人弹出验证码(虽然我们本来就是机器人)
   await page.waitFor(2500)
  }
  // 所有的数据爬取完毕后关闭浏览器
  await browser.close()
  log(chalk.green(&#39;服务正常结束&#39;))
  // 这是一个在内部声明的函数,之所以在内部声明而不是外部,是因为在内部可以获取相关的上下文信息,如果在外部声明我还要传入 page 这个对象
  async function handleData() {
   // 现在我们进入浏览器内部搞些事情,通过page.evaluate方法,该方法的参数是一个函数,这个函数将会在页面内部运行,这个函数的返回的数据将会以Promise的形式返回到外部 
   const list = await page.evaluate(() => {
    
    // 先声明一个用于存储爬取数据的数组
    const writeDataList: IWriteData[] = []
    // 获取到所有的商品元素
    let itemList = document.querySelectorAll('.item.J_MouserOnverReq')
    // 遍历每一个元素,整理需要爬取的数据
    for (let item of itemList) {
     // 首先声明一个爬取的数据结构
     let writeData: IWriteData = {
      picture: undefined,
      link: undefined,
      title: undefined,
      price: undefined
     }
     // 找到商品图片的地址
     let img = item.querySelector('img')
     writeData.picture = img.src
     // 找到商品的链接
     let link: HTMLAnchorElement = item.querySelector('.pic-link.J_ClickStat.J_ItemPicA')
     writeData.link = link.href
     // 找到商品的价格,默认是string类型 通过~~转换为整数number类型
     let price = item.querySelector('strong')
     writeData.price = ~~price.innerText
     
     // 找到商品的标题,淘宝的商品标题有高亮效果,里面有很多的span标签,不过一样可以通过innerText获取文本信息
     let title: HTMLAnchorElement = item.querySelector('.title>a')
 
     writeData.title = title.innerText
     // 将这个标签页的数据push进刚才声明的结果数组
     writeDataList.push(writeData)
    }
    // 当前页面所有的返回给外部环境
    return writeDataList
    
   })
   // 得到数据以后写入到mongodb
   const result = await mongo.insertMany('GTX1080', list)
   log(chalk.yellow('写入数据库完毕'))
  }
 } catch (error) {
  // 出现任何错误,打印错误消息并且关闭浏览器
  console.log(error)
  log(chalk.red('服务意外终止'))
  await browser.close()
 } finally {
  // 最后要退出进程
  process.exit(0)
 }
}

Penser

1 Pourquoi utiliser Typescript ?

Comme Typescript est si facile à utiliser, je ne peux pas mémoriser toutes les API de Puppeteer, et je ne veux pas les vérifier toutes, je peux donc utiliser TS pour obtenir des rappels intelligents et éviter être stupide à cause d'une faute d'orthographe. Fondamentalement, après avoir utilisé TS, vous pouvez retaper le code

puppeteer.png

2. Quel est le problème de performances du un robot ?

Étant donné que Puppeteer démarrera un navigateur et exécutera la logique interne, cela prend beaucoup de mémoire. En regardant la console, ce processus de nœud occupe environ 300 Mo de mémoire.

Mes pages sont explorées une par une. Si vous souhaitez explorer plus rapidement, vous pouvez démarrer plusieurs processus. Notez que V8 est monothread, cela n'a donc aucun sens d'ouvrir plusieurs pages dans un seul processus. doit être configuré pour ouvrir différents processus de nœuds. Bien sûr, cela peut également être implémenté via le cluster de nœuds (cluster). L'essence est la même
J'ai également défini différents temps d'attente pendant le processus d'exploration. c'est pour Attendre le chargement de la page Web, d'une part, pour empêcher Taobao de reconnaître que je suis un code de vérification de bombe à chenilles

Autres fonctions de Puppeteer

.

Ici, nous n'utilisons que quelques fonctionnalités de base de Puppeteer. En fait, Puppeteer a plus de fonctions. Par exemple, la fonction de traitement sur le nœud est introduite pour être exécutée dans le navigateur et la page actuelle est enregistrée sous forme d'image pdf ou png. Et vous pouvez également lancer un navigateur avec des effets d'interface via const browser = wait puppeteer.launch({ headless: false }), et vous pourrez voir comment fonctionne votre robot. De plus, pour certains sites Web qui nécessitent une connexion, si vous ne souhaitez pas confier le code de vérification à un tiers pour le traitement, vous pouvez également désactiver le mode sans tête, puis définir le temps d'attente dans le programme et effectuer manuellement une vérification pour atteindre l’objectif de connexion.

Bien sûr, Google a produit une bibliothèque géniale, qui n'est pas seulement utilisée pour explorer les données. Cette bibliothèque est également utilisée pour certaines analyses automatisées des performances, les tests d'interface, la surveillance frontale des sites Web, etc.

4. Quelques autres réflexions

En général, créer un robot pour explorer des données est un projet d'exercice relativement complexe qui teste de nombreuses compétences de base. Il a été utilisé à plusieurs reprises dans ce domaine. crawler Lorsqu'il s'agit d'async, cela nécessite une compréhension complète de l'async, de Promise et d'autres connaissances connexes. Lors de l'analyse du DOM pour collecter des données, j'ai également utilisé plusieurs fois des méthodes natives pour obtenir les attributs du DOM (si le site Web a jquery, vous pouvez également l'utiliser directement, sinon, une injection externe est requise. Certaines configurations sont requises sous dactylographié pour éviter les rapports variables $ non reconnues. De cette manière, le DOM peut être manipulé via la syntaxe jquery), et la maîtrise des API liées au DOM a été examinée.

De plus, il ne s'agit que d'une programmation orientée processus. Nous pouvons l'encapsuler complètement dans une classe pour le fonctionnement. Cela teste également la compréhension de la POO d'ES

Je pense que vous l'avez maîtrisé après avoir lu. C'est le cas dans cet article. Pour des méthodes plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !

Lecture recommandée :

Un résumé de la façon d'utiliser l'objet d'état de vuex

Comment utiliser Angular pour lancer un composant

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn