我写了一个自动化脚本涨粉,从0阅读到接近100粉丝(一)

简介: 我写了一个自动化脚本涨粉,从0阅读到接近100粉丝

引言


在CSDN写了大概140篇文章,一直都是0阅读量,仿佛石沉大海,在掘金能能频频上热搜的文章,在CSDN一点反馈都没有,所以跟文章质量关系不大,主要是曝光量,后面调研一下,发现情况如下

image.png

好家伙,基本都是人机评论,后面问了相关博主,原来都是互相刷评论来涨阅读量,enen...,原来CSDN是这样的,真无语,竟然是刷评论,那么就不要怪我用脚本了。


效果如下


image.png


puppeteer入门


先来学习一波puppeteer知识点,其实也不难


puppeteer 简介


Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包, 用来模拟 Chrome 浏览器的运行。

Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。 Chromium 和 Chrome区别

在学puppeteer之前我们先来了解下 headless chrome


什么是 Headless Chrome


  • 在无界面的环境中运行 Chrome
  • 通过命令行或者程序语言操作 Chrome
  • 无需人的干预,运行更稳定
  • 在启动 Chrome 时添加参数 --headless,便可以 headless 模式启动 Chrome
alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"  # Mac OS X 命令别名
chrome --headless --disable-gpu --dump-dom https://www.baidu.com               # 获取页面 DOM
chrome --headless --disable-gpu --screenshot https://www.baidu.com    # 截图

查看更多chrome启动参数 英文中文


puppeteer 能做什么


官方称:“Most things that you can do manually in the browser can be done using Puppeteer”,那么具体可以做些什么呢?

  • 网页截图或者生成 PDF
  • 爬取 SPA 或 SSR 网站
  • UI 自动化测试,模拟表单提交,键盘输入,点击等行为
  • 捕获网站的时间线,帮助诊断性能问题
  • ......


puppeteer 结构


image.png

  • Puppeteer 使用 DevTools 协议 与浏览器进行通信。
  • Browser 实例可以拥有浏览器上下文。
  • BrowserContext 实例定义了一个浏览会话并可拥有多个页面。
  • Page 至少有一个框架:主框架。 可能还有其他框架由 iframe 或 框架标签 创建。
  • frame 至少有一个执行上下文 - 默认的执行上下文 - 框架的 JavaScript 被执行。 一个框架可能有额外的与 扩展 关联的执行上下文。


puppeteer 运行环境


查看 Puppeteer 的官方 API 你会发现满屏的 async, await 之类,这些都是 ES7 的规范,所以你需要: Nodejs 的版本不能低于 v7.6.0

bash

npm install puppeteer 
# or "yarn add puppeteer"

Note: 当你安装 Puppeteer 时,它会自动下载Chromium,由于Chromium比较大,经常会安装失败~ 可是使用以下解决方案

  • 把npm源设置成国内的源 cnpm taobao 等
  • 安装时添加--ignore-scripts命令跳过Chromium的下载  npm install puppeteer --ignore-scripts
  • 安装 puppeteer-core 这个包不会去下载Chromium


puppeteer 基本用法


先打开官方的入门demo

const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});
  await browser.close();
})();

上面这段代码就实现了网页截图,先大概解读一下上面几行代码:

  1. 先通过 puppeteer.launch() 创建一个浏览器实例 Browser 对象
  2. 然后通过 Browser 对象创建页面 Page 对象
  3. 然后 page.goto() 跳转到指定的页面
  4. 调用 page.screenshot() 对页面进行截图
  5. 关闭浏览器

是不是觉得好简单?


puppeteer.launch(options)


options 参数详解

参数名称 参数类型 参数说明
ignoreHTTPSErrors boolean 在请求的过程中是否忽略 Https 报错信息,默认为 false
headless boolean 是否以”无头”的模式运行 chrome, 也就是不显示 UI, 默认为 true
executablePath string 可执行文件的路劲,Puppeteer 默认是使用它自带的 chrome webdriver, 如果你想指定一个自己的 webdriver 路径,可以通过这个参数设置
slowMo number 使 Puppeteer 操作减速,单位是毫秒。如果你想看看 Puppeteer 的整个工作过程,这个参数将非常有用。
args Array(String) 传递给 chrome 实例的其他参数,比如你可以使用”–ash-host-window-bounds=1024x768” 来设置浏览器窗口大小。
handleSIGINT boolean 是否允许通过进程信号控制 chrome 进程,也就是说是否可以使用 CTRL+C 关闭并退出浏览器.
timeout number 等待 Chrome 实例启动的最长时间。默认为30000(30秒)。如果传入 0 的话则不限制时间
dumpio boolean 是否将浏览器进程stdout和stderr导入到process.stdout和process.stderr中。默认为false。
userDataDir string 设置用户数据目录,默认linux 是在 ~/.config 目录,window 默认在 C:\Users{USER}\AppData\Local\Google\Chrome\User Data, 其中 {USER} 代表当前登录的用户名
env Object 指定对Chromium可见的环境变量。默认为process.env。
devtools boolean 是否为每个选项卡自动打开DevTools面板, 这个选项只有当 headless 设置为 false 的时候有效


puppeteer如何使用


下面介绍 10 个关于使用 Puppeteer 的用例,并在介绍用例的时候会穿插的讲解一些 API,告诉大家如何使用 Puppeteer:


01 获取元素及操作


如何获取元素?

  • page.$('#uniqueId'):获取某个选择器对应的第一个元素
  • page.$$('div'):获取某个选择器对应的所有元素
  • page.$x('//img'):获取某个 xPath 对应的所有元素
  • page.waitForXPath('//img'):等待某个 xPath 对应的元素出现
  • page.waitForSelector('#uniqueId'):等待某个选择器对应的元素出现

Page.$(selector) 获取单个元素,底层是调用的是 document.querySelector() , 所以选择器的 selector 格式遵循 css 选择器规范

Page.$$(selector) 获取一组元素,底层调用的是 document.querySelectorAll(). 返回 Promise(Array(ElemetHandle)) 元素数组.

const puppeteer = require('puppeteer');
async function run (){
    const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1366,height:768}});
    const page = await browser.newPage();
    await page.goto('https://www.baidu.com');
    const input_area = await page.$("#kw");
    await input_area.type("Hello Wrold");
    const search_btn = await page.$('#su');
    await search_btn.click();
}
run();


02 获取元素属性


Puppeteer 获取元素属性跟我们平时写前段的js的逻辑有点不一样,按照通常的逻辑,应该是现获取元素,然后在获取元素的属性。但是上面我们知道 获取元素的 API 最终返回的都是 ElemetHandle 对象,而你去查看 ElemetHandle 的 API 你会发现,它并没有获取元素属性的 API.

事实上 Puppeteer 专门提供了一套获取属性的 API, Page.$eval() 和 Page.$$eval()

Page.$$eval(selector, pageFunction[, …args]), 获取单个元素的属性,这里的选择器 selector 跟上面 Page.$(selector) 是一样的。

const value = await page.$eval('input[name=search]', input => input.value);
const href = await page.$eval('#a", ele => ele.href);
const content = await page.$eval('.content', ele => ele.outerHTML);
const puppeteer = require('puppeteer');
async function run (){
    const browser = await puppeteer.launch({headless:false,defaultViewport:{width:1366,height:768}});
    const page = await browser.newPage();
    await page.goto('https://www.baidu.com');
    const input_area = await page.$("#kw");
    await input_area.type("Hello Wrold");
    const search_btn = await page.$('#su');
    await search_btn.click();
    await page.waitFor('div#content_left > div.result-op.c-container.xpath-log',{visible:true});
    let resultText = await page.$eval('div#content_left > div.result-op.c-container.xpath-log',ele=> ele.innerText)
    console.log("result Text= ",resultText);
}
run();


03 处理多个元素


const puppeteer = require('puppeteer');
async function run() {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: {
      width: 1280,
      height: 800,
    },
    slowMo: 200,
  });
  const page = await browser.newPage();
  await page.goto('https://www.baidu.com');
  const input_area = await page.$('#kw');
  await input_area.type('Hello Wrold');
  await page.keyboard.press('Enter');
  const listSelector = 'div#content_left > div.result-op.c-container.xpath-log';
  // await page.waitForSelector(listSelector);
  await page.waitFor(3 * 1000);
  const list = await page.$$eval(listSelector, (eles) =>
    eles.map((ele) => ele.innerText)
  );
  console.log('List ==', list);
}
run();


04 切换frame


一个 Frame 包含了一个执行上下文(Execution Context),我们不能跨 Frame 执行函数,一个页面中可以有多个 Frame,主要是通过 iframe 标签嵌入的生成的。其中在页面上的大部分函数其实是 page.mainFrame().xx 的一个简写,Frame 是树状结构,我们可以通过page.frames()获取到页面所有的 Frame,如果想在其它 Frame 中执行函数必须获取到对应的 Frame 才能进行相应的处理

const puppeteer = require('puppeteer')
async function anjuke(){
    const browser = await puppeteer.launch({headless:false});
    const page = await browser.newPage();
    await page.goto('https://login.anjuke.com/login/form');
    // 切换iframe
    await page.frames().map(frame => {console.log(frame.url())})
    const targetFrameUrl = 'https://login.anjuke.com/login/iframeform'
    const frame =  await page.frames().find(frame => frame.url().includes(targetFrameUrl));
    const phone= await frame.waitForSelector('#phoneIpt')
    await phone.type("13122022388")
}
anjuke();


05 拖拽验证码操作


const puppeteer = require('puppeteer')
async function aliyun(){
    const browser = await puppeteer.launch({headless:false,ignoreDefaultArgs:['--enable-automation']});
    const page = await browser.newPage();
    await page.goto('https://account.aliyun.com/register/register.htm',{waitUntil:"networkidle2"});
    const frame = await page.frames().find(frame=>{
        console.log(frame.url())
        return frame.url().includes('https://passport.aliyun.com/member/reg/fast/fast_reg.htm')
    })
    const span = await frame.waitForSelector('#nc_1_n1z');
    const spaninfo = await span.boundingBox();
    console.log('spaninfo',spaninfo)
    await page.mouse.move(spaninfo.x,spaninfo.y);
    await page.mouse.down();
    const div = await frame.waitForSelector('div#nc_1__scale_text > span.nc-lang-cnt');
    const divinfo = await div.boundingBox();
    console.log('divinfo',divinfo)
    for(var i=0;i<divinfo.width;i++){
        await page.mouse.move(spaninfo.x+i,spaninfo.y);
    }
    await page.mouse.up();
}
aliyun();

目录
相关文章
|
2天前
|
存储 Python
Python自动化脚本编写指南
【10月更文挑战第38天】本文旨在为初学者提供一条清晰的路径,通过Python实现日常任务的自动化。我们将从基础语法讲起,逐步引导读者理解如何将代码块组合成有效脚本,并探讨常见错误及调试技巧。文章不仅涉及理论知识,还包括实际案例分析,帮助读者快速入门并提升编程能力。
13 2
|
4天前
|
运维 监控 Python
自动化运维:使用Python脚本简化日常任务
【10月更文挑战第36天】在数字化时代,运维工作的效率和准确性成为企业竞争力的关键。本文将介绍如何通过编写Python脚本来自动化日常的运维任务,不仅提高工作效率,还能降低人为错误的风险。从基础的文件操作到进阶的网络管理,我们将一步步展示Python在自动化运维中的应用,并分享实用的代码示例,帮助读者快速掌握自动化运维的核心技能。
12 3
|
10天前
|
运维 监控 应用服务中间件
自动化运维:如何利用Python脚本提升工作效率
【10月更文挑战第30天】在快节奏的IT行业中,自动化运维已成为提升工作效率和减少人为错误的关键技术。本文将介绍如何使用Python编写简单的自动化脚本,以实现日常运维任务的自动化。通过实际案例,我们将展示如何用Python脚本简化服务器管理、批量配置更新以及监控系统性能等任务。文章不仅提供代码示例,还将深入探讨自动化运维背后的理念,帮助读者理解并应用这一技术来优化他们的工作流程。
|
11天前
|
运维 监控 Linux
自动化运维:如何利用Python脚本优化日常任务##
【10月更文挑战第29天】在现代IT运维中,自动化已成为提升效率、减少人为错误的关键技术。本文将介绍如何通过Python脚本来简化和自动化日常的运维任务,从而让运维人员能够专注于更高层次的工作。从备份管理到系统监控,再到日志分析,我们将一步步展示如何编写实用的Python脚本来处理这些任务。 ##
|
15天前
|
运维 Prometheus 监控
自动化运维之路:从脚本到DevOps
【10月更文挑战第25天】在数字化时代的浪潮中,运维不再是简单的服务器管理,而是成为了企业竞争力的核心。本文将带你走进自动化运维的世界,探索如何通过技术手段提升效率和稳定性,以及实现快速响应市场的能力。我们将一起学习如何从基础的脚本编写进化到全面的DevOps实践,包括工具的选择、流程的优化以及文化的建设。无论你是运维新手还是资深专家,这篇文章都将为你提供有价值的见解和实用的技巧。
16 3
|
17天前
|
JSON 测试技术 持续交付
自动化测试与脚本编写:Python实践指南
自动化测试与脚本编写:Python实践指南
22 1
|
1月前
|
人工智能 运维 Devops
自动化运维之路:从脚本到DevOps的转变
【10月更文挑战第7天】在这篇文章中,我们将一起探索自动化运维的演变历程,从最初的简单脚本到现代的DevOps实践。我们将深入理解自动化如何改变了运维工作的本质,并讨论实现这一转变的关键技术和策略。文章将不包含代码示例,而是聚焦于理念、工具和方法论的介绍,旨在为读者提供一个全面的自动化运维框架视图。
|
1月前
|
人工智能 运维 监控
自动化运维:从脚本到工具的演变之路
【10月更文挑战第8天】在数字化时代的浪潮中,运维不再是简单的硬件维护,它已经演变成一场关于效率、稳定性和创新的技术革命。本文将带您领略自动化运维的魅力,从最初的脚本编写到现代复杂的自动化工具,我们将一探究竟,看看这些工具如何帮助运维人员简化日常任务,提升工作效率,并最终推动业务发展。
|
28天前
|
监控 关系型数据库 MySQL
PowerShell 脚本编写 :自动化Windows 开发工作流程
PowerShell 脚本编写 :自动化Windows 开发工作流程
24 0
|
1月前
|
Web App开发 安全 Java
网页内容获取:Scala自动化脚本的实现
网页内容获取:Scala自动化脚本的实现