您现在的位置是:网站首页> 开发积累
日常开发技术收集积累
- 开发积累
- 2024-08-19
- 368人已阅读
日常开发技术收集积累
基于Windows的Kafka有关环境搭建、以及使用.NET环境开发的案例代码与演示
微信还能接入HTTP协议?定制微信机器人,做消息推送,AI聊天
正片叠底(Multiply)和滤色(Screen)是两种基本的混合模式
扫描连接WIFI
生成播放视频的URL的二维码,用户扫描开始播放视频,播放完后展示连接WIFI二维码,用户手动扫码连接
小程序实现设置WIFI
/**
* 页面的初始数据
*/
data: {
wifiname:'wifi商家',
ssid: '@Ruijie-sDE3D',
bssid: '0',
password: '12345678',
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log("111",options)
var wifiname = options.wifiname
var qssid = options.alias;
// var qbssid = options.bssid;
var qpassword = options.wifipass;
this.setData({
wifiname:wifiname,
ssid: qssid,
// bssid: qbssid,
password: qpassword
})
var that = this
},
/**
* 点击连接按钮触发
*/
connectWifi: function() {
const that = this;
wx.showToast({
title: '请稍等',
icon: 'loading',
duration: 500//持续的时间
})
that.startWiFi();
},
/**
* 加载WiFi模块
*/
startWiFi: function() {
const that = this;
wx.startWifi({
complete: (res) => {
that.connected();
},
})
},
/**
* 连接WiFi
*/
connected: function() {
const that = this;
wx.connectWifi({
SSID: that.data.ssid,
// BSSID: that.data.bssid,
password: that.data.password,
success: () => {
wx.showToast({
title: 'WiFi连接成功',
})
// 跳转至成功页面
wx.redirectTo({
url: '/pages/success/success',
})
},
fail: (res) => {
that.errorDialog(res);
}
})
},
/**
* 连接失败弹窗
* @param {错误返回} res
*/
errorDialog: function(res) {
const that = this;
wx.showModal({
title: '连接失败',
content: '连接失败请打开wifi或复制连接',
confirmText: '复制密码',
success (res) {
if (res.confirm) {
that.copyPassword();
} else if (res.cancel) {
console.log('cancel')
}
},
fail(res) {
wx.showToast({
title: res.errMsg,
})
}
});
},
/**
* 复制密码到剪贴板
*/
copyPassword: function() {
const that = this;
wx.setClipboardData({
data: that.data.password,
success (res) {
wx.getClipboardData({
success (res) {
console.log(res.data);
}
})
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
高并发场景设计
设计一个高并发秒杀场景需要考虑以下几个方面
1.数据库设计:选择适合高并发场景的数据库,如使用关系型数据库时可以采用分库分表的方式来提高数据库的读写性能。可以使用缓存技术来减轻数据库的压力,如使用Redis缓存热门商品信息。
2.队列系统:引入消息队列系统可以有效地削峰填谷,平衡请求的处理速度和系统的承载能力。秒杀请求可以先进入消息队列,再由后台异步处理,避免直接对数据库进行高并发的读写操作。
3.缓存优化:使用缓存来存储热门商品的库存信息,减少对数据库的频繁访问。可以使用分布式缓存,如Redis,来提高读取速度。
4.分布式系统:采用分布式架构来分担系统的负载,将请求分散到多个服务器上进行处理。可以使用负载均衡技术,如Nginx,进行请求的分发,保证每个服务器的压力均衡。
5.限流与排队:为了保护系统的稳定性,可以对请求进行限流,限制每秒的请求数量。同时,可以为每个用户分配一个唯一的标识符,通过排队系统来控制用户的访问顺序,避免系统被过多的请求拖垮。
6.异步处理:将秒杀请求的处理过程异步化,如使用消息队列、多线程等方式,保证请求的快速响应,避免阻塞其他请求的处理。
7.前端优化:通过前端技术,如CDN加速、页面静态化等,减少对后端的请求,提高用户访问的响应速度。可以采用前端缓存技术,如Local Storage,将商品信息缓存在前端,减少对后端的请求次数。
8.安全措施:为避免恶意请求和刷单行为,可以引入验证码、IP限制、用户身份验证等安全措施,保障系统的公平性和安全性。
以上是设计高并发秒杀场景的一些思路,具体的设计方案还需根据实际需求和系统架构进行详细的规划和实施。
在高并发场景下,常用的可靠任务队列
1.RabbitMQ:RabbitMQ是一个流行的开源消息队列系统,支持多种消息传输协议,如AMQP、MQTT等。它具有高可靠性、可持久化、分布式和高并发处理能力,适用于各种异步任务和消息传递场景。Kafka是一个分布式的发布-订阅消息系统,能够支撑海量数据的数据传递。在离线和实时的消 息处理业务系统中,Kafka都有广泛的应用。Kafka将消息持久化到磁盘中,并对消息创建了备份保证了 数据的安全。Kafka在保证了较高的处理速度的同时,又能保证数据处理的低延迟和数据的零丢失。
2.Apache Kafka:Kafka是一个分布式的流处理平台,也可以用作可靠的消息队列。Kafka以高吞吐量、持久性和可扩展性而闻名,适用于大规模数据处理和实时流处理场景。
3.Redis:Redis是一个内存中的数据结构存储系统,也可以用作消息队列。它支持发布/订阅模式和列表数据结构,可用于处理高并发的任务队列。
4.Apache ActiveMQ:ActiveMQ是一个基于Java的开源消息队列系统,支持多种消息传输协议,如AMQP、STOMP等。它具有高可用性、可靠性和扩展性,适用于异步任务处理和分布式系统集成。
5.Amazon Simple Queue Service (SQS):SQS是亚马逊提供的一项托管消息队列服务,具有高度可靠性和可伸缩性。它支持标准队列和先入先出队列,适用于分布式系统和云计算环境。
这些可靠任务队列都具有不同的特点和适用场景,选择适合自己项目需求的队列系统需要综合考虑系统架构、可用性、性能要求和开发语言等因素。
总结
1:吞吐量较低:Kafka和RabbitMQ都可以。
2:吞吐量高:Kafka
以下是一个使用C#操作Kafka的可靠任务队列的简单示例:
首先,你需要安装NuGet包来引入Kafka相关库。使用Visual Studio的话,可以通过NuGet包管理器添加以下两个包:
Confluent.Kafka:提供了Kafka的客户端库。
Confluent.Kafka.Serialization:提供了Kafka消息的序列化和反序列化支持。
接下来,可以使用以下代码示例来创建一个生产者(Producer)和一个消费者(Consumer):
using Confluent.Kafka;
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
string bootstrapServers = "localhost:9092"; // Kafka服务器地址和端口
string topic = "my-topic"; // Kafka主题名称
// 生产者
var producerConfig = new ProducerConfig { BootstrapServers = bootstrapServers };
using (var producer = new ProducerBuilder<Null, string>(producerConfig).Build())
{
// 发送消息
var message = new Message<Null, string> { Value = "Hello Kafka" };
var deliveryReport = producer.ProduceAsync(topic, message).Result;
Console.WriteLine($"Message delivered to {deliveryReport.TopicPartitionOffset}");
// 等待消息发送完成
producer.Flush(TimeSpan.FromSeconds(10));
}
// 消费者
var consumerConfig = new ConsumerConfig
{
BootstrapServers = bootstrapServers,
GroupId = "my-group",
AutoOffsetReset = AutoOffsetReset.Earliest
};
using (var consumer = new ConsumerBuilder<Ignore, string>(consumerConfig).Build())
{
// 订阅主题
consumer.Subscribe(topic);
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true; // 阻止进程退出
cts.Cancel();
};
try
{
// 消费消息
while (true)
{
var consumeResult = consumer.Consume(cts.Token);
Console.WriteLine($"Received message: {consumeResult.Message.Value}");
}
}
catch (OperationCanceledException)
{
// 用户取消操作
}
finally
{
consumer.Close();
}
}
}
}
在这个示例中,我们创建了一个生产者来发送消息到指定的Kafka主题,然后创建了一个消费者来订阅该主题并接收消息。你可以根据自己的需求进行扩展和修改。
请确保将bootstrapServers设置为你的Kafka服务器地址和端口,将topic设置为你要使用的主题名称。此外,你还可以根据实际需求配置其他的Kafka相关参数。
这只是一个简单的示例,实际使用中可能需要更多的错误处理和配置。你可以参考Confluent.Kafka库的文档和示例来深入了解C#操作Kafka的更多功能和用法。
原理
人员标签,信息标签,人员和信息标签的匹配
人员和信息的标签定时更改
以人员看信息多的同一标签做人员标签(点赞,评论做加权)
信息标签也是以看的人多的共同标签打标签
定时多长时间对信息和个人打标签,何时信息标签打完毕
实现
信息发布预热期,作者自己打的标签,首推送关注者,再次符合标签的人员
远程桌面解决断开后UI交互问题
query session
tscon rdp-tcp#0 /dest:console
给机器人分配一个远程账户,登录进去后执行连接到本地
日常维护的用另一个远程账户
微信还能接入HTTP协议?定制微信机器人,做消息推送,AI聊天
3.9.2.23版本微信
提取码:1234
如何防止线上活动优惠券被仿
可在二维码加上加密的时间戳和个人信息等,时间验证个人信息验证,同时也可让用户输入密码验证使用优惠券
免费地图解决方案
国家地理信息公共服务平台 天地图
凯立德官网
维智物联全域定位
图炫(aimap.gl)地图可视化
http://location-dev.newayz.com/aimap-gl-v2/docs/
多媒体开发知识积累
正片叠底(Multiply)和滤色(Screen)是两种基本的混合模式
正片叠底(Multiply)和滤色(Screen)是两种基本的混合模式,分别用于使图片变暗和变亮。它们之间的组合还可以形成更复杂的混合模式,如叠加(Overlay)和柔光(Soft Light)。
正片叠底 —— 就是把两层图像的像素相乘,最后会得到一个更暗的图像。这个模式是对称的,也就是说交换基色和混合色得到的结果是一样的。
,其中a是基色,b是混合色。
滤色 —— 首先把两层图像的像素值取互补数,然后将它们相乘,最后再去互补数。这和正片叠底得到的结果是相反的。它会得到一个更亮的图像。
,其中a是基色,b是混合色。
叠加 —— 结合了正片叠底和滤色两种混合模式。基色中亮色的部分会更加亮,而暗色的部分会更暗。
,其中a是基色,b是混合色
Puppeteer相关技术收集
Puppeteer 简介
1、Puppeteer 简介
2、运行环境
- Nodejs 的版本不能低于 v7.6.0, 需要支持 async, await.
- 需要最新的 chrome driver, 这个你在通过 npm 安装 Puppeteer 的时候系统会自动下载的
npm install puppeteer --save
3、基本用法
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(); })();
- 先通过 puppeteer.launch() 创建一个浏览器实例 Browser 对象
- 然后通过 Browser 对象创建页面 Page 对象
- 然后 page.goto() 跳转到指定的页面
- 调用 page.screenshot() 对页面进行截图
- 关闭浏览器
3.1 puppeteer.launch(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 的时候有效 |
3.2 Browser 对象
const puppeteer = require('puppeteer'); puppeteer.launch().then(async browser => { // 保存 Endpoint,这样就可以重新连接 Chromiumconst browserWSEndpoint = browser.wsEndpoint(); // 从Chromium 断开连接 browser.disconnect(); // 使用endpoint 重新和 Chromiunm 建立连接 const browser2 = await puppeteer.connect({browserWSEndpoint}); // Close Chromium await browser2.close();});
方法名称 | 返回值 | 说明 |
browser.close() | Promise | 关闭浏览器 |
browser.disconnect() | void | 断开浏览器连接 |
browser.newPage() | Promise(Page) | 创建一个 Page 实例 |
browser.pages() | Promise(Array(Page)) | 获取所有打开的 Page 实例 |
browser.targets() | Array(Target) | 获取所有活动的 targets |
browser.version() | Promise(String) | 获取浏览器的版本 |
browser.wsEndpoint() | String | 返回浏览器实例的 socket 连接 URL, 可以通过这个 URL 重连接 chrome 实例 |
4、Puppeteer 实战
- 打开京东首页
- 将光标 focus 到搜索输入框
- 键盘点击输入文字
- 点击搜索按钮
- 打开京东首页
- 找到输入框的 input 元素
- 设置 input 的值为要搜索文字
- 触发搜索按钮的单机事件
- 打开京东首页
- 输入“手机”关键字并搜索
- 获取前10个商品的 A 标签,并获取 href 属性值,获取商品详情链接
- 分别打开10个商品的详情页,截取网页图片
4.1 获取元素
let inputElement = await page.$("#search", input => input); //下面写法等价 let inputElement = await page.$('#search');
const links = await page.$$("a"); //下面写法等价 const links = await page.$$("a", links => links);
4.2 获取元素属性
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);
4.3 执行自定义的 JS 脚本
const result = await page.evaluate(() => { return Promise.resolve(8 * 7); }); console.log(result); // prints "56"
(async () => { const browser = await puppeteer.launch({headless:true}); const page = await browser.newPage(); await page.goto('https://jr.dayi35.com'); await page.setViewport({width:1920, height:1080}); const documentSize = await page.evaluate(() => { return { width: document.documentElement.clientWidth, height : document.body.clientHeight, } }) await page.screenshot({path:"example.png", clip : {x:0, y:0, width:1920, height:documentSize.height}}); await browser.close(); })();
const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window)); //aindowHandle Handle for the window object. const aHandle = await page.evaluateHandle('document'); // Handle for the 'document'.
const aHandle = await page.evaluateHandle(() => document.body); const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle); console.log(await resultHandle.jsonValue()); await resultHandle.dispose();
4.4 Page.exposeFunction
const docSize = await page.evaluate(()=> { function getPageSize() { return { width: document.documentElement.clientWidth, height : document.body.clientHeight, } } return getPageSize(); });
const puppeteer = require('puppeteer'); const crypto = require('crypto'); puppeteer.launch().then(async browser => { const page = await browser.newPage(); page.on('console', msg => console.log(msg.text)); await page.exposeFunction('md5', text => crypto.createHash('md5').update(text).digest('hex') ); await page.evaluate(async () => { // use window.md5 to compute hashes const myString = 'PUPPETEER'; const myHash = await window.md5(myString); console.log(`md5 of ${myString} is ${myHash}`);}); await browser.close(); });
const puppeteer = require('puppeteer'); const fs = require('fs'); puppeteer.launch().then(async browser => { const page = await browser.newPage(); page.on('console', msg => console.log(msg.text)); await page.exposeFunction('readfile', async filePath => { return new Promise((resolve, reject) => { fs.readFile(filePath, 'utf8', (err, text) => { if (err) reject(err); else resolve(text); }); }); }); await page.evaluate(async () => { // use window.readfile to read contents of a file const content = await window.readfile('/etc/hosts'); console.log(content); }); await browser.close(); });
5、Page.emulate 修改模拟器(客户端)运行配置
- Page.setViewport() 修改浏览器视窗大小
- Page.setUserAgent() 设置浏览器的 UserAgent 信息
- Page.emulateMedia() 更改页面的CSS媒体类型,用于进行模拟媒体仿真。 可选值为 “screen”, “print”, “null”, 如果设置为 null 则表示禁用媒体仿真。
- Page.emulate() 模拟设备,参数设备对象,比如 iPhone, Mac, Android 等
page.setViewport({width:1920, height:1080}); //设置视窗大小为 1920x1080 page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'); page.emulateMedia('print'); //设置打印机媒体样式
const puppeteer = require('puppeteer'); const devices = require('puppeteer/DeviceDescriptors'); const iPhone = devices['iPhone 6']; puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.emulate(iPhone); await page.goto('https://www.google.com'); // other actions... await browser.close();});
6、键盘和鼠标
- keyboard.down(key[, options]) 触发 keydown 事件
- keyboard.press(key[, options]) 按下某个键,key 表示键的名称,比如 ‘ArrowLeft’ 向左键,详细的键名映射请戳这里
- keyboard.sendCharacter(char) 输入一个字符
- keyboard.type(text, options) 输入一个字符串
keyboard.up(key) 触发 keyup 事件
page.keyboard.press("Shift"); //按下 Shift 键
page.keyboard.sendCharacter('嗨');
page.keyboard.type('Hello'); // 一次输入完成
page.keyboard.type('World', {delay: 100}); // 像用户一样慢慢输入
鼠标操作:
- mouse.click(x, y, [options]) 移动鼠标指针到指定的位置,然后按下鼠标,这个其实 mouse.move 和 mouse.down 或 mouse.up 的快捷操作
- mouse.down([options]) 触发 mousedown 事件,options 可配置:
- options.button 按下了哪个键,可选值为[left, right, middle], 默认是 left, 表示鼠标左键
- options.clickCount 按下的次数,单击,双击或者其他次数
- delay 按键延时时间
- mouse.move(x, y, [options]) 移动鼠标到指定位置, options.steps 表示移动的步长
- mouse.up([options]) 触发 mouseup 事件
7、另外几个有用的 API
7.1 Page.waitFor 系列 API
- page.waitFor(selectorOrFunctionOrTimeout[, options[, …args]]) 下面三个的综合 API
- page.waitForFunction(pageFunction[, options[, …args]]) 等待 pageFunction 执行完成之后
- page.waitForNavigation(options) 等待页面基本元素加载完之后,比如同步的 HTML, CSS, JS 等代码
- page.waitForSelector(selector[, options]) 等待某个选择器的元素加载之后,这个元素可以是异步加载的,这个 API 非常有用,你懂的。
await page.waitForSelector('.gl-item'); //等待元素加载之后,否则获取不到异步加载的元素
const links = await page.$$eval('.gl-item > .gl-i-wrap > .p-img > a', links => {
return links.map(a => {
return {
href: a.href.trim(),
name: a.title
}
});
});
7.2 page.getMetrics()
- Timestamp 度量标准采样的时间戳
- Documents 页面文档数
- Frames 页面 frame 数
- JSEventListeners 页面内事件监听器数
- Nodes 页面 DOM 节点数
- LayoutCount 页面布局总数
- RecalcStyleCount 样式重算数
- LayoutDuration 所有页面布局的合并持续时间
- RecalcStyleDuration 所有页面样式重新计算的组合持续时间。
- ScriptDuration 所有脚本执行的持续时间
- TaskDuration 所有浏览器任务时长
- JSHeapUsedSize JavaScript 占用堆大小
- JSHeapTotalSize JavaScript 堆总量
8、总结和源码
//延时函数
function sleep(delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(1)
} catch (e) {
reject(0)
}
}, delay)
})
}
const puppeteer = require('puppeteer');
puppeteer.launch({
ignoreHTTPSErrors:true,
headless:false,slowMo:250,
timeout:0}).then(async browser => {
let page = await browser.newPage();
await page.setJavaScriptEnabled(true);
await page.goto("https://www.jd.com/");
const searchInput = await page.$("#key");
await searchInput.focus(); //定位到搜索框
await page.keyboard.type("手机");
const searchBtn = await page.$(".button");
await searchBtn.click();
await page.waitForSelector('.gl-item'); //等待元素加载之后,否则获取不异步加载的元素
const links = await page.$$eval('.gl-item > .gl-i-wrap > .p-img > a', links => {
return links.map(a => {
return {
href: a.href.trim(),
title: a.title
}
});
});
page.close();
const aTags = links.splice(0, 10);
for (var i = 1; i < aTags.length; i++) {
page = await browser.newPage()
page.setJavaScriptEnabled(true);
await page.setViewport({width:1920, height:1080});
var a = aTags[i];
await page.goto(a.href, {timeout:0}); //防止页面太长,加载超时
//注入代码,慢慢把滚动条滑到最底部,保证所有的元素被全部加载
let scrollEnable = true;
let scrollStep = 500; //每次滚动的步长
while (scrollEnable) {
scrollEnable = await page.evaluate((scrollStep) => {
let scrollTop = document.scrollingElement.scrollTop;
document.scrollingElement.scrollTop = scrollTop + scrollStep;
return document.body.clientHeight > scrollTop + 1080 ? true : false
}, scrollStep);
await sleep(100);
}
await page.waitForSelector("#footer-2014", {timeout:0}); //判断是否到达底部了
let filename = "images/items-"+i+".png";
//这里有个Puppeteer的bug一直没有解决,发现截图的高度最大只能是16384px, 超出部分被截掉了。
await page.screenshot({path:filename, fullPage:true});
page.close();
}
browser.close();
});
await page.setUserAgent(fake.user_agent())
可以看到 HTTP 状态码 为 403(403 Forbidden),即使我们设置了 User-Agent,美团依然能够检测到 WebDriver。
Pyppeteer 的 Page 对象有一个 evaluateOnNewDocument 方法,可以在每次加载网页的时候执行某个语句,此处执行将 WebDriver 隐藏的命令
browser = await launch({headless: False,
args: ['--disable-infobars']
})
page = await browser.newPage()
await page.setUserAgent(fake.user_agent())
await page.evaluateOnNewDocument('function(){Object.defineProperty(navigator, "webdriver", {get: () => undefined})}')
await page.goto(URL, options={'timeout': 10000})
await asyncio.sleep(412)
await browser.close()
Puppeteer一些高级玩儿法
用户数据持久化
平时访问网站时关键 Cookies 已经保存到本地浏览器,因此下次登录时可以直接读取并保持登录状态,这些信息保存在用户目录下,其不仅包含浏览器的基本配置信息,还有一些 Cache、Cookies 等信息,若能在浏览器启动时读取这些信息,则可以恢复一些历史记录以及登录状态信息。
Pyppeteer 提供了实现手段,即在启动的时候设置 userDataDir:
import asyncio
from faker import Faker
from pyppeteer import launch
fake = Faker()
URL = 'https://www.zhihu.com/'
async def main():
browser = await launch({'headless': False,
'args': ['--disable-infobars'],
'userDataDir': './userdata'
})
page = await browser.newPage()
await page.setViewport({'width': 1530, 'height': 800})
await page.setUserAgent(fake.user_agent())
await page.evaluateOnNewDocument('function(){Object.defineProperty(navigator, "webdriver", {get: () => undefined})}')
await page.goto(URL, options={'timeout': 10000})
await asyncio.sleep(412)
await browser.close()
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
第一次启动时先手动登录:
登录后相关信息会保存在用户目录下,下次登录时即可直接读取:
此后再启动,无需重新登录(除非 Cookies 过期)。
Browser
launch 方法返回的是 Browser 对象(浏览器对象),即 Browser 类的一个实例,其拥有许多用于操作浏览器的方法。
无痕模式
无痕模式的好处就是环境干净,不与其他的浏览器示例共享 Cache、Cookies 等内容,其开启方式可以通过 createIncognitoBrowserContext 方法,其返回一个 context 对象,用其创建新选项卡:
import asyncio
from faker import Faker
from pyppeteer import launch
fake = Faker()
URL = 'https://gz.meituan.com/meishi/'
async def main():
browser = await launch({'headless': False,
'args': ['--disable-infobars'],
'userDataDir': './userdata'
})
context = await browser.createIncognitoBrowserContext()
page = await context.newPage()
await page.setViewport({'width': 1530, 'height': 800})
await page.setUserAgent(fake.user_agent())
await page.evaluateOnNewDocument('function(){Object.defineProperty(navigator, "webdriver", {get: () => undefined})}')
await page.goto(URL, options={'timeout': 10000})
await asyncio.sleep(412)
await browser.close()
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
通过Puppeteer实现滚动加载
/* 引入相关 工具 */
const fs = require('fs')
const cheerio = require('cheerio')
const puppeteer = require('puppeteer')
/* 定义函数 */
let getListData = async function(Category) {
/* 初始化 puppeteer*/
const browser = await puppeteer.launch({
executablePath: 'D:\\chrome-win\\chrome.exe',//把项目中的这个chrome-win文件夹放到D盘根目录
headless: false //这个是 是否打开chrome可视化窗口 true是不打开 false是打开
})
//获取page实例
const page = await browser.newPage()
//我这里是通过 入参传过来的 分类来判断抓取相应页面的数据
let url = ''
switch (Category) {
case '0':
url = 'https://www.toutiao.com/ch/news_game/'
break;
case '1':
url = 'https://www.toutiao.com/ch/news_entertainment/'
break;
case '2':
url = 'https://www.toutiao.com/ch/news_history/'
break;
case '3':
url = 'https://www.toutiao.com/ch/news_finance/'
break;
}
//打开页面
await page.goto(url)
//定义页面内容及Jquery
var content , $
/* 页面滚动方法 */
async function scrollPage(i) {
content = await page.content();
$ = cheerio.load(content);
/*执行js代码(滚动页面)*/
await page.evaluate(function () {
/* 这里做的是渐进滚动,如果一次性滚动则不会触发获取新数据的监听 */
for (var y = 0; y <= 1000*i; y += 100) {
window.scrollTo(0,y)
}
})
// 获取数据列表
const li = $($('.feedBox').find('ul')[0]).find('li')
return li
}
let i = 0
let li = await scrollPage(++i)
//如果数据列表 不够30 则一直获取
while (li.length < 30) {
li = await scrollPage(++i)
}
let data = {
list: []
}
/* 封装返回的数据*/
li.map(function (index,item) {
$(item).find('img').attr('src') != undefined ?
data.list.push({
src: $(item).find('img').attr('src'),
title: $($(item).find('.title')).text(),
source:$($(item).find('.source')).text(),
href:$($(item).find('.title')).attr('href')
}):''
})
//顺手存入本地文件
fs.writeFileSync('tt.JSON',JSON.stringify(data))
fs.writeFileSync('tt.html',content)
/* 关闭 puppeteer*/
await browser.close()
return data
}
module.exports = getListData
通过API将图片上传到免费图床-遇见图床
通过API将图片上传到免费图床-遇见图床
C# async 函数
public async static void GetInfoAsync()
{
Task<bool> task = Task.Run<bool>(() =>
{
Thread.Sleep(10000); //模拟耗时
return true;
});
//以下两种方式
bool taskResult1 = await task; //内部自己执行了GetAwaiter()
bool taskResult = task.GetAwaiter().GetResult(); //自己手动执行Awaiter(), 但是阻塞UI
Console.WriteLine(taskResult);
}
一个上传文件的例子
async Task<string> UpFile()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
//添加字符串参数,参数名为qq
//content.Add(new StringContent("123456"), "qq");
string path = "g:\\1.png";// Path.Combine(System.Environment.CurrentDirectory, "1.png");
//添加文件参数,参数名为files,文件名为123.png
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(path));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
content.Add(fileContent, "image", "123.png");
content.Add(new StringContent("chaoneng"), "apiType");
content.Add(new StringContent("14ff9ab178c34097ff171964fdb166f4"), "token");
var requestUri = new Uri("https://www.hualigs.cn/api/upload"); //"https://www.hualigs.cn/api/upload";
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| (SecurityProtocolType)0x300 //Tls11
| (SecurityProtocolType)0xC00; //Tls12
var response = await client.PostAsync(requestUri, content);
string url = "";
if (response.IsSuccessStatusCode)
{
Console.WriteLine("上传成功!");
var result = response.Content.ReadAsStringAsync().Result;
//MessageBox.Show(result);
try
{
Hashtable m_HH = JsonHelper.JsonStrToOBJ<Hashtable>(result);
if (m_HH.ContainsKey("code"))
{
string code = m_HH["code"].ToString();
if (code == "200")
{
if (m_HH.ContainsKey("data"))
{
Hashtable m_dataHH = JsonHelper.OBJToType<Hashtable>(m_HH["data"]);
if (m_dataHH.ContainsKey("url"))
{
Hashtable m_urlHH = JsonHelper.OBJToType<Hashtable>(m_dataHH["url"]);
if (m_urlHH.ContainsKey("distribute"))
{
Console.WriteLine(m_urlHH["distribute"].ToString());
//MessageBox.Show(m_urlHH["distribute"].ToString());
url = m_urlHH["distribute"].ToString();
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
else
{
string str = "错误码:" + code;
if (m_HH.ContainsKey("msg"))
{
str += "," + m_HH["msg"].ToString();
}
MessageBox.Show(str);
}
}
else
{
MessageBox.Show("数据解析异常:" + result);
}
}
catch
{
}
}
else
{
MessageBox.Show("上传异常");
}
/*
Task<string> task = Task.Run<string >(() =>
{
return url;
});
*/
return url;
}
async private void button29_Click(object sender, EventArgs e)
{
string str = await UpFile();
MessageBox.Show(str);
}
防止恶意访问攻击
写一个异常访问ip清洗工具,1、同一时刻60s内请求超过60以上直接封禁该ip 100分钟,2、禁止所有国外ip和港、澳、台等地方IP。3、放进来的ip 随机进行滑块验证机器人,没通过的直接放入验证ip队列,该ip请求必须通过验证才会被从验证队列释放。4、静态媒体资源可以放到公共免费平台 用url跨站调用。5、网站只暴露一个入口,该页面加入js验证用户是否是机器人的算法,通过算法 请求后台生成jwt加密失效密钥,token通过cookie存在用户端,token有效期内可以浏览网站其他页面,负责跳转首页面。
各大地图厂商收费,免费解决方案
如果只用地图展示类,3种都满足,天地图有些丑罢了,凯立德和WAYZ和高德的风格蛮像;
如果有导航类需求那就凯立德了;
如果有设备需要接入定位,那WAYZ更方便接入
用天地图就好了,国家的,免费
所谓的支付宝/微信支付“云面签”原理
市面上最近流行所谓的“云免签”,只需要收款人在其提供云免签服务的平台上传支付宝/微信二维码,不需要收款人在PC端或手机上安装监控支付宝/微信支付结果通知的程序,然后由云端来帮助监控支付结果。
研究了一下各种“云免签”方案,大致分为几种方案:
1、微信店员模式
收款人作为店主,让收款人添加提供云免签服务的平台的微信号为店员,由于店主收款消息都会自动通知店员,因此只需要在店员端监听支付结果就行,不需要店主始终在线。
由于支付宝只允许一个店员属于一个店主,因此此种模式对支付宝成本过高。
2、监听支付宝/微信网页端模式
提供云免签服务的平台获取支付宝/微信PC网页版扫码登陆二维码,让收款人扫码登陆,提供云免签服务的平台在服务器端通过扫收款人账单来获取支付结果。
3、支付宝当面支付+当面付分账功能
这些方案还有诸多细节需要考虑,例如怎么自动化通过店员请求、怎样保持支付宝/微信登陆状态等等。
C#框架相关笔记
返回状态码
StatusCode = 200;
ctx.Response.StatusCode = StatusCode;//验证通过调用
ctx.Response.End();
大型分布式系统设计初版
大型分布式系统设计初版
人员数据落到各个节点,新数据落的规则按一致性hash决定见后面
业务数据落到各个节点,新数据落的规则按地理位置范围和表数据量和hash落到那个节点具体见后
中心业务数据地理位置库分布规则表
业务数据保存两份,按地理位置保存 按人员保存
用户共享数据节点如角色等 业务数据共享节点如栏目等
用户的归宿 如群 谁创建群,群数据落点在那个用户节点
所有的新落点按一致性hash权重获得
所有节点多个从库
关于共享数据的缓存,角色 栏目等
各区数据中心
节点ID规则 uuid+数据中心id+节点编号
数据中心所拥有的数据节点服务 调用节点服务认证
redis 数据缓存服务
redis 消息服务
Redis分布式锁
数据级缓存,页面级缓存
数据库节点服务 对应所在数据中心
根据用户id或接入IP或业务数据id 获得数据链接节点根据数据中心
栏目归宿 共享 角色 地理范围 权限 看 发 回复 购买
获得web模块的页面部分html
用户访问过程
未登录状态访问:
主gate服务根据用户IP引导用户访问最近的相对闲置web节点,根据用户的地理位置拉取相应范围内栏目及数据(根据地理位置获得数据中心,根据数据中心获得相对闲置的数据服务节点 拉取数据)
用户切换地理位置同上只是位置不再通过IP而根据用户选择引导用户访问最近相对闲置的web 节点后续相同
用户登陆访问
根据全局用户名对应的用户ID获得用户信息所在数据中心获得数据节点服务拉取用户基础数据及权限数据,根据地理位置拉取业务栏目数据流程如上
信息发布,在地理位置所在数据中心拿取相对闲置的数据库节点添加数据,同时往用户所在数据节点添加相应数据,数据回复交易等类式 回复记录节点交易等与记录关联数据位于同一数据节点
直播App架构
上一篇:收集实用开发接口