乱码三千 – 分享实用IT技术

乱码三千 – 码出一个新世界


  • 首页

  • 归档

  • 搜索

向谷歌搜索引擎主动推送网页的教程 Google Indexing API 接口实现

发表于 2020-09-08

谷歌搜索引擎作为全球第一的搜索引擎早就支持了站长主动推送的功能,只不过不是面向普通用户的可视化界面,而是通过编程API接口实现的,有很多站长并不是专业的开发者,但由于谷歌需要验证网站所有权,所以我不能直接做一个可视化界面让站长自己填写自己的秘钥,所以只能对谷歌的接口进行二次封装,以降低使用的难度。

源码项目地址:https://github.com/NeilRen/GoogleIndexing

环境要求

首先,我是以Java为平台进行的封装,JDK版本为1.8,其他程序可能需要中间层才能打通,还不如自己实现,其他编程语言的同学我也没有办法,这个世界上编程语言太多了。

其次,谷歌的Google Indexing API接口在中国大陆无法访问,所以程序需要运行在可以访问谷歌的网络环境中。

前提条件

首先,你需要一个谷歌账号。你的项目是Java的,并且JDK为1.8以上。

创建 Google API 项目

然后在向 Indexing API 发送请求之前,您需要告知 Google 您的客户端并激活对 Indexing API 的访问权限。谷歌为我们提供了一个设置向导,设置向导会引导您在 Google API 控制台中创建项目、启用 Indexing API 以及创建凭据。

首先先跟着向导创建一个项目

Google Indexing API 设置向导

然后转到凭据,添加凭据

Google Indexing API 添加凭证

添加的凭据选择Indexing API、网页服务器(例如 node.js、Tomecat),选择应用数据,点击“我需要哪些凭据?”到下一页

Google Indexing API 为项目添加凭证

创建一个服务账号,名称可以自己起一个名字,秘钥类型选择JSON,点击继续

Google Indexing API 创建服务账号

选择创建无角色账号即可

Google Indexing API 创建无角色账号

这时就会自动下载一个json文件,这个就是我们的私钥,要保存好

Google Indexing API 秘钥

在 Search Console 中验证网站所有权

我们还需要到 Search Console 添加我们的网站,验证所有权,验证成功以后,注意我们要去旧版的控制台,不要去新版的控制台!然后添加所有者

Google 旧版控制台]

所有者的邮箱填写我们上一步获得的私钥JSON文件中的邮箱地址。

Google Indexing API 秘钥JSONGoogle 添加网站所有者

在自己的项目中安装依赖

如果您使用Apache Maven来管理Java项目,只需在项目的pom.xml文件加入相应的依赖项即可。您只需在pom.xml中声明以下依赖:

1
2
3
4
5
<dependency>
<groupId>net.renfei</groupId>
<artifactId>googleindexing</artifactId>
<version>1.0.0</version>
</dependency>

编写代码调用服务,在实例化GoogleIndexing的时候,需要传一个String参数,这个参数是私钥JSON文件所在的文件地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.alibaba.fastjson.JSON;
import com.google.api.services.indexing.v3.model.UrlNotificationMetadata;
import net.renfei.googleindexing.GoogleIndexing;
import net.renfei.googleindexing.entity.UrlNotification;
import net.renfei.googleindexing.entity.UrlNotificationType;

public class Demo {
public static void main(String[] args) {
try {
GoogleIndexing googleIndexing = new GoogleIndexing("/Users/renfei/Google/Ren-Fei-5a8df7c2b912.json");
UrlNotification urlNotification = new UrlNotification();
urlNotification.setUrl("https://www.renfei.net");
urlNotification.setType(UrlNotificationType.URL_UPDATED);
UrlNotificationMetadata urlNotificationMetadata = googleIndexing.publish(urlNotification);
System.out.printf(JSON.toJSONString(urlNotificationMetadata));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Hugo博客百度SEO优化 自动提交

发表于 2020-09-08

在切换到Hugo平台之后,比较头疼的是之前hexo很多seo的插件不能使用了. 下面跟大家说一下我的seo优化方案.

Meta标签优化

Description

meta description,被认为是最有用的meta标签,是网站的简介信息。 content控制在100个字符以内比较好。

1
<meta name='description' itemprop="description" content="{{ if .Description }}{{ .Description }}{{ else }}{{if .IsPage}}{{substr .Summary 0 100}}{{ end }}{{ end }}">

Keywords

1
2
3
4
5
{{ if .Keywords }} 
<meta name="keywords" content="{{ delimit .Keywords ", " }}" >
{{else}}
<meta name="keywords" content="{{ delimit .Site.Params.Keywords ", " }}" >
{{ end }}

百度熊掌号推送

说到seo熊掌号是必不可少的了,他可以做到24小时之内收录.所以这个必须不能放过.

gulp

在这里我要使用gulp来做我的自动化任务管理工具

安装gulp需要的模块

1
2
3
4
npm init
npm install gulp --save
npm install xml2js --save
npm install xmlhttprequest --save

在项目根目录创建一个gulpfile.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 导入相关依赖
const gulp = require("gulp");
const fs = require('fs');
const xml2js = require('xml2js')
const parser = new xml2js.Parser();
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;


// 注册百度站长与熊掌号,百度会提供下面的数据给你
var xz_appid = '1623792852327580';
var xz_token = 'bbd1f589b763b7fb40e52628c176ae27';
var baidu_token= '79IKQsDuvZSdXwd9'

//熊掌号每天需要提交的url数量
// 注意这个数字必须要跟百度允许提交的url数量一致,如果多了会提交失败.
const xzCount = 2000


// 创建一个任务
gulp.task('baiduSeo', () => {
// 读取sitemap.xml文件并且转换成json
fs.readFile(__dirname + '/public/sitemap.xml', function(err, data) {
parser.parseString(data, function (err, result) {
// 把读取的数据传入这个函数
urlSubmit(result.urlset.url)
console.log('Done');
});
});
});

// 提交url的方法
function urlSubmit(urls) {
// 最新内容提交
var new_target = "http://data.zz.baidu.com/urls?appid="+xz_appid+"&token="+xz_token+"&type=realtime"

// 历史提交
var history_target = "http://data.zz.baidu.com/urls?appid="+xz_appid+"&token="+xz_token+"&type=batch"

// 百度站长
var baidu_target = "http://data.zz.baidu.com/urls?site=https://zaina.newban.cn&token="+baidu_token

// MIP
var MIP_target = "http://data.zz.baidu.com/urls?site=https://zaina.newban.cn&token="+baidu_token+"&type=mip"

// AMP
var AMP_target = "http://data.zz.baidu.com/urls?site=https://zaina.newban.cn&token="+baidu_token+"&type=amp"

// 最新url,看熊掌号情况而定
urls = urls.map(item=>item.loc[0])
allUrls = urls.join('\n')

var new_urls_Arr = urls.slice(0,xzCount)
new_urls= new_urls_Arr.join('\n');

console.info('百度站长开始提交',new_urls)
sendData(baidu_target,new_urls,'百度站长提交成功')

console.info('熊掌号开始提交')
//sendData(new_target,new_urls,'熊掌号提交完成')

// 提交历史url 每天最多500w条
console.info("历史数据开始提交")
//sendData(history_target,allUrls,"历史数据提交完成")

console.info("MIP 开始提交")
//sendData(MIP_target,allUrls,"MIP提交成功")

console.info("AMP 开始提交")
//sendData(AMP_target,allUrls,"AMP提交成功")

// 提交数据
function sendData(target,urls,message){
var xhr = new XMLHttpRequest();
xhr.open('POST', target, false);
xhr.setRequestHeader('Content-type', 'text/plain');
xhr.onload = function () {
console.log(this.responseText);
if(message){console.info(message)}
};
xhr.send(urls);
}

};

gulp.task("default",gulp.series( 'baiduSeo',function(){}))

配置好以上都文件之后

推送

1
2
3
4
# 博客生成
hugo
# url推送
gulp

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Python的.sort()方法和sorted()比较总结

发表于 2020-09-07

1,.sort()方法

  使用方式是:列表.sort(),作用是将原来的列表正序排序,所以它是对原来的列表进行的操作,不会产生一个新列表,例如:

1
2
3
4
5
6
7
8
9
10
11
12
import  random
numList=[]
print(numList)
for i in range(10):
numList.append(random.randrange(1,10))# 不包括10
print("未排序的列表:",numList)
# numList.sort()执行过程是将列表拍完序后又赋值给了原列表
numList.sort()
print("排序后列表:",numList)
# 无法将numList.sort()赋值给一个新列表,以为它并不返回一个新列表
numList=numList.sort()
print("无法赋值给新列表的的结果:",numList)

执行结果:

1
2
3
未排序的列表: [7, 2, 2, 4, 5, 6, 7, 9, 4, 8]
排序后列表: [2, 2, 4, 4, 5, 6, 7, 7, 8, 9]
无法赋值给新列表的的结果: None

2,sorted(列表),是Python内置函数,该函数对原列表不会产生影响,只是在原来列表的基础上,产生一个有序的新列表,可以复制一个列表名

1
2
3
4
5
6
7
8
9
10
11
import  random
numList=[]
print(numList)
for i in range(10):
numList.append(random.randrange(1,10))# 不包括10
print("未排序的列表:",numList)

sorted(numList)
print("sorted排序后的数组,不会对原列表有任何影响:",numList)
getList=sorted(numList)
print("sorted获得的新的列表:",getList)

执行结果:

1
2
3
未排序的列表: [1, 4, 3, 4, 3, 9, 5, 4, 4, 9]
sorted排序后的数组,不会对原列表有任何影响: [1, 4, 3, 4, 3, 9, 5, 4, 4, 9]
sorted获得的新的列表: [1, 3, 3, 4, 4, 4, 4, 5, 9, 9]

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

App自动化之Appium入门

发表于 2020-09-07

像Selenium可以操控Web浏览器,手机APP平台也有类似的自动化测试工具:Appium;
全文分基础介绍、环境搭建和案例演示三部分介绍Appium,以帮助Learner快速的上手。

基础介绍

Appium是一个开源的自动化测试框架,用于原生,混合和移动Web应用程序。 它使用WebDriver协议驱动iOS,Android和Windows应用程序。关于它的运作流程,用图来介绍会更加生动形象一些:

Appium运行流程、原理

在上图中,左边这部分是Appium-Client,通俗点来说,是用于间接驱动最右边的设备执行预定的自动化测试流程,支持使用多种主流的编程语言进行编写,这也是测试开发人员需要关注的核心部分;中间的Appium-Server是衔接左边客户端以及右边APP设备端的重要桥梁,一般仅需要配置好环境及启动运行;右边这块,当然就是实际执行自动化测试的终端,如IOS真机、Android真机,或者是模拟器。

环境搭建

  • NodeJS

Appium是使用nodejs实现的,因此Node是解释器,首先要确认安装好

  • Appium-Server
    • nodejs
    • appium-desktop

上述的两种方式都可以搭建Appium-Server环境,后面演示会基于Appium-Desktop。(PS:下载太慢了?分享个百度网盘)

  • Andrioid SDK
    • android sdk
    • android studio

上述方式可以直接和间接搭建安装Android环境,因为后面要用到adb这个工具,所以需要配置好ANDROID_HOME这个环境变量。(PS:下载太慢了?分享个百度网盘)

  • Appium-Python-Client

后面会用到Python来编写Appium客户端:pip install Appium-Python-Client

okay,准备好以上几个环境后,启动Appium测试一下:

Appium Desktop Server

Appium Desktop Server

案例演示

下面演示在安卓真机上的自动登录Keep(APP)。

  1. 获取设备名称。操作流程:开启手机的开发和调试模式,连接电脑授权认证,Window + R输入并运行cmd,用adb devices -l查看:

获取设备号

  1. 启动Appium Server进行调试:

Inspector Session

Desired Capabilities

从上图可以看到,启动App Session需要有以下几个参数(点击了解更详细的Appium Desired Capabilities):

  • platformName,如Android、iOS等
  • deviceName,参考前面是如何获取的
  • appPackage和appActivity,获取参考这里

综上所述,这里对应Keep的信息如下:

1
2
3
4
5
6
{
"platformName": "Android",
"deviceName": "WAS_AL00",
"appPackage": "com.gotokeep.keep",
"appActivity": "com.gotokeep.keep.splash.SplashActivity"
}

点击Start Session,之后可以看到手机端启动了Keep,并且在Appium Server端中同步展示:

Start Session

Keep

上述的操作通常只是用来方便获取控件id及定位的,下面基于Python编写完整的Appium-Client以实现自动登录操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

server = 'http://localhost:4723/wd/hub' # Appium Server, 端口默认为4723
desired_capabilities = {
'platformName': 'Android',
'deviceName': 'WAS_AL00', # 需替换成你的deviceName
'appPackage': 'com.gotokeep.keep',
'appActivity': 'com.gotokeep.keep.splash.SplashActivity'
}

driver = webdriver.Remote(server, desired_capabilities)
wait = WebDriverWait(driver, 10) # 最大查找等待超时时间:10s


def get_permission():
"""允许APP获取的某些权限"""

try:
ask = wait.until(EC.presence_of_element_located((By.ID, 'com.android.packageinstaller:id/do_not_ask_checkbox')))
ask.click()
allow = wait.until(
EC.presence_of_element_located((By.ID, 'com.android.packageinstaller:id/permission_allow_button')))
allow.click()
except:
pass


# 允许两项授权
get_permission()
get_permission()

# 点击“立即使用”
welcome = wait.until(EC.presence_of_element_located((By.ID, 'com.gotokeep.keep:id/btn_bottom_in_video_welcome')))
welcome.click()

# 切换“密码登录”(同样可以使用第三方进行授权登录)
driver.tap([(900, 110)])

# 输入“手机号”
phone = driver.find_element_by_accessibility_id('Phone Number In Login')
phone.send_keys('13988888888') # 替换成实际的账号

# 输入“密码”
password = driver.find_element_by_accessibility_id('Password In Login')
password.send_keys('123456') # 替换成实际的密码

# 点击“登录”
login = driver.find_element_by_id('com.gotokeep.keep:id/btn_action')
login.click()

最后,附上运行效果图:

效果图

本文转载自;https://blog.mariojd.cn/get-started-with-appium.html

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Python跨平台之将Python 程序打包成Windows和Linux可执行文件

发表于 2020-09-07

通常执行 python 程序要有相应的 Python 环境,但某些特定场景下,我们可能并不愿意这么麻烦的去配置这些环境(比如将写好的脚本发给客户进行操作),如果可以提前将程序打包成 Windows平台的 .exe 文件或者是Linux下的 .sh 脚本,那么使用起来就会方便很多,py2exe 和 PyInstaller 这两款工具都是干这么个事的,下面以 hello.py 脚本(代码内容如下)为例进行介绍。

1
2
age = input("How old are you?\n")
print("A: " + age)

提示:PyInstaller 可以在 Windows 和 Linux 下使用,更推荐使用,而 py2exe 暂不支持 Linux 平台 而且只支持python低版本环境

PyInstaller

  1. 安装
1
pip install pyinstaller
  1. 使用

常见的用法有:

  • 生成单个可执行文件:pyinstaller -F hello.py
  • 生成指定icon的可执行文件:pyinstaller -i xxx.ico hello.py

在当前目录下的 dist 文件夹内可以找到生成后的可执行文件(脚本),更多用法请参考说明

py2exe

  1. 安装
1
pip install py2exe
  1. 使用

如上图,打包失败了,留意到这里说不支持 python3.6,果断放弃,有兴趣的可以自行降低到 python3.4 或 python3.5 进行尝试。

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

wireshark怎么抓包、wireshark抓包详细图文教程

发表于 2020-09-07

wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。使用wireshark的人必须了解网络协议,否则就看不懂wireshark了。
为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。

wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容,总结,如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark.

wireshark 开始抓包

开始界面

img

wireshark是捕获机器上的某一块网卡的网络包,当你的机器上有多块网卡的时候,你需要选择一个网卡。

点击Caputre->Interfaces.. 出现下面对话框,选择正确的网卡。然后点击”Start”按钮, 开始抓包

img

Wireshark 窗口介绍

img

WireShark 主要分为这几个界面

\1. Display Filter(显示过滤器), 用于过滤

\2. Packet List Pane(封包列表), 显示捕获到的封包, 有源地址和目标地址,端口号。 颜色不同,代表

\3. Packet Details Pane(封包详细信息), 显示封包中的字段

\4. Dissector Pane(16进制数据)

\5. Miscellanous(地址栏,杂项)

img

使用过滤是非常重要的, 初学者使用wireshark时,将会得到大量的冗余信息,在几千甚至几万条记录中,以至于很难找到自己需要的部分。搞得晕头转向。

过滤器会帮助我们在大量的数据中迅速找到我们需要的信息。

过滤器有两种,

一种是显示过滤器,就是主界面上那个,用来在捕获的记录中找到所需要的记录

一种是捕获过滤器,用来过滤捕获的封包,以免捕获太多的记录。 在Capture -> Capture Filters 中设置

保存过滤

在Filter栏上,填好Filter的表达式后,点击Save按钮, 取个名字。比如”Filter 102”,

img

Filter栏上就多了个”Filter 102” 的按钮。

img

过滤表达式的规则

表达式规则

\1. 协议过滤

比如TCP,只显示TCP协议。

\2. IP 过滤

比如 ip.src ==192.168.1.102 显示源地址为192.168.1.102,

ip.dst==192.168.1.102, 目标地址为192.168.1.102

\3. 端口过滤

tcp.port ==80, 端口为80的

tcp.srcport == 80, 只显示TCP协议的愿端口为80的。

\4. Http模式过滤

http.request.method==”GET”, 只显示HTTP GET方法的。

\5. 逻辑运算符为 AND/ OR

常用的过滤表达式

过滤表达式 用途
http 只查看HTTP协议的记录
ip.src ==192.168.1.102 or ip.dst==192.168.1.102 源地址或者目标地址是192.168.1.102
snmp && udp.dstport == 162 抓取SNMP Trap包

封包列表(Packet List Pane)

封包列表的面板中显示,编号,时间戳,源地址,目标地址,协议,长度,以及封包信息。 你可以看到不同的协议用了不同的颜色显示。

你也可以修改这些显示颜色的规则, View ->Coloring Rules.

img

封包详细信息 (Packet Details Pane)

这个面板是我们最重要的,用来查看协议中的每一个字段。

各行信息分别为

Frame: 物理层的数据帧概况

Ethernet II: 数据链路层以太网帧头部信息

Internet Protocol Version 4: 互联网层IP包头部信息

Transmission Control Protocol: 传输层T的数据段头部信息,此处是TCP

Hypertext Transfer Protocol: 应用层的信息,此处是HTTP协议

img

TCP包的具体内容

从下图可以看到wireshark捕获到的TCP包中的每个字段。

img

看到这, 基本上对wireshak有了初步了解, 现在我们看一个TCP三次握手的实例

三次握手过程为

img

这图我都看过很多遍了, 这次我们用wireshark实际分析下三次握手的过程。

打开wireshark, 打开浏览器输入 http://www.cr173.com

在wireshark中输入http过滤, 然后选中GET /tankxiao HTTP/1.1的那条记录,右键然后点击”Follow TCP Stream”,

这样做的目的是为了得到与浏览器打开网站相关的数据包,将得到如下图

img

图中可以看到wireshark截获到了三次握手的三个数据包。第四个包才是HTTP的, 这说明HTTP的确是使用TCP建立连接的。

第一次握手数据包

客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接。 如下图

第二次握手的数据包

服务器发回确认包, 标志位为 SYN,ACK. 将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即0+1=1, 如下图

第三次握手的数据包

客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1, 如下图:

就这样通过了TCP三次握手,建立了连接

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

使用python利用第三方登录实现自动化简书发布文章

发表于 2020-09-07

话不多说 首先附上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import time

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait

import re

import linecache


class Main(object):
# init
def __init__(self, file):
self.title = ''
self.content = ''
self.category = ''
self.tags = ''
# OsChina的系统分类, 设个默认值
self.osChina_sys_category = '编程语言'
# CSDN的文章分类, 设个默认值
self.csdn_article_category = '原创'
# CSDN的博客分类, 设个默认值
self.csdn_blog_category = '后端'
self.read_file(file)

# 读取MD中的title, content, self_category, self_tags, osChina_sys_category, csdn_article_category, csdn_blog_category
def read_file(self, markdown_file):
self.title = linecache.getline(markdown_file, 2).split('title: ')[1].strip('\n')
with open(markdown_file, 'r', encoding='UTF-8') as f:
self.content = f.read().split('-->\n')[1]
# 重置文件指针偏移量
f.seek(0)
for line in f.readlines():
if re.search('self_category: ', line) is not None:
self.category = line.split('self_category: ')[1].strip('\n')
elif re.search('self_tags: ', line) is not None:
self.tags = line.split('self_tags: ')[1].strip('\n')
elif re.search('osChina_sys_category: ', line) is not None:
self.osChina_sys_category = line.split('osChina_sys_category: ')[1].strip('\n')
elif re.search('csdn_article_category: ', line) is not None:
self.csdn_article_category = line.split('csdn_article_category: ')[1].strip('\n')
elif re.search('csdn_blog_category: ', line) is not None:
self.csdn_blog_category = line.split('csdn_blog_category: ')[1].strip('\n')




# QQ授权登录, 使用前提是QQ客户端在线
def qq(driver, timeout):
# 切换到最新打开的窗口
window_handles = driver.window_handles
driver.switch_to.window(window_handles[-1])

print('qq authorize title is ', driver.title)

# 切换iframe
iframe = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_id('ptlogin_iframe'))
driver.switch_to.frame(iframe)

# 点击头像进行授权登录
login = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//*[@id="qlogin_list"]/a[1]'))
login.click()
# 简书
class JianShu(object):
@staticmethod
def post(main, timeout, self_timeout=3):
# 1.跳转登陆
login = 'https://www.jianshu.com/sign_in'
driver = webdriver.Chrome()
driver.get(login)

# 2.窗口最大化
driver.maximize_window()

# 3.使用QQ授权登录
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div/div/ul/li[3]/a/i').click()
driver.close()
qq(driver, timeout)

# 4.点击"写文章"
write_blog = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('/html/body/nav/div/a[2]'))
write_blog = WebDriverWait(driver, timeout).until(lambda d: d.find_elements_by_class_name('/html/body/nav/div/a[2]'))
write_blog.click()
driver.close()
time.sleep(3)
# window_handles = driver.window_handles
#driver.switch_to.window(window_handles[-1])

# 5.点击指定分类
classify = WebDriverWait(driver, timeout).until(lambda d: d.find_elements_by_class_name('_3DM7w'))
for c in classify:
html = c.get_attribute('innerHTML')
if main.category in html:
c.click()
else:
# TODO 如果分类不存在,还可以直接新建分类
pass

# 6.点击'新建文章'
time.sleep(self_timeout)
new_article = WebDriverWait(driver, timeout).until(
lambda d: d.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[1]/div/div/div/div[1]/i'))
new_article.click()
article = WebDriverWait(driver, timeout).until(
lambda d: d.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[1]/div/div/div/ul/li[1]'))
article.click()

# 7.填写标题, 内容
time.sleep(self_timeout)
title = driver.find_element_by_class_name('_24i7u')
title.clear()
title.send_keys(main.title)
content = driver.find_element_by_id('arthur-editor')
content.clear()
content.send_keys(main.content)

# 8.保存草稿
driver.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[2]/div/div/div/div/ul/li[8]/a').click()
# 8.发布文章
# driver.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[2]/div/div/div/div/ul/li[1]/a').click()


if __name__ == '__main__':
md_file = 'auto.md'
print("Markdown File is ", md_file)

timeout = 30
main = Main(md_file)

# 简书
jian_shu = JianShu()
jian_shu.post(main, timeout)

PS:Selenium操纵浏览器是依赖于浏览器驱动程序的,不同版本的浏览器需要下载不同版本的驱动, 否则程序无法运行, 下面贴出的是谷歌和火狐浏览器驱动程序的下载地址。

Chrome ( chromedriver ) Firefox ( geckodriver )
官方下载 官方下载
淘宝镜像 淘宝镜像
备用下载 备用下载

关于谷歌驱动的下载安装, 详情可参见文章《Web自动化框架selenium的介绍与使用》

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

如何在浏览器中手动设置cookies值实现前端分离调试

发表于 2020-09-07

在前端开发中经常会碰到需要cookies调试的情况, 下面介绍一下如何在浏览器中手动设置cookies值

img

1.查看cookies值

1
document.cookie

2.设置cookies值

1
document.cookie='name=Jack';

3.给cookies设置有效时间 默认浏览器关闭失效

1
2
3
var oDate=new Date();
oDate.setDate(oDate.getDate()+7);//设置为当前时间起算7天后过期
document.cookie='name=Jack;expires='+oDate.toGMTString();

4.移除cookies

1
setCookie(key,"",-1);//把cookie设置为过期

函数封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function setCookie(key,value,t){
var oDate=new Date();
oDate.setDate(oDate.getDate()+t);
document.cookie=key+"="+value+"; expires="+oDate.toDateString();

}
function getCookie(key){
var arr1=document.cookie.split("; ");//由于cookie是通过一个分号+空格的形式串联起来的,所以这里需要先按分号空格截断,变成[name=Jack,pwd=123456,age=22]数组类型;
for(var i=0;i<arr1.length;i++){
var arr2=arr1[i].split("=");//通过=截断,把name=Jack截断成[name,Jack]数组;
if(arr2[0]==key){
return decodeURI(arr2[1]);
}
}

//封装一个移除cookie的函数
function removeCookie(key){
setCookie(key,"",-1);//把cookie设置为过期

}

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

如何设置通过Postman实现API网关的请求签名与调试

发表于 2020-09-07

前言
Postman是一个非常强大的HTTP发包测试工具, 目前Postman已经提供了Windows/Mac/Linux系统的客户端的下载,使用很方便。不过API网关的调试,需要对HTTP请求进行签名才能调用,无法使用简单的curl等发包工具完成,但我们可以使用Postman工具提供的Pre-request Script脚本来实现API网关的签名功能,实现API的调试功能,本文主要介绍如何使用Postman调试API网关接口。

核心代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
var appKey = "<YOUR APP KEY>";
var appSecret = "<YOUR APP SECRET>";

var md5 = calcMd5();
var date = new Date().toString();
var nonce = createUuid();

var textToSign = "";
textToSign += request.method + "\n";
textToSign += request.headers["accept"] + "\n";
textToSign += md5 + "\n";
textToSign += request.headers["content-type"] + "\n";
textToSign += date + "\n";

var headers = headersToSign();
var signatureHeaders;
var sortedKeys = Array.from(headers.keys()).sort()
for (var headerName of sortedKeys) {
textToSign += headerName + ":" + headers.get(headerName) + "\n";
signatureHeaders = signatureHeaders ? signatureHeaders + "," + headerName : headerName;
}
textToSign += urlToSign();
console.log("textToSign\n" + textToSign.replace(/\n/g, "#"));
var hash = CryptoJS.HmacSHA256(textToSign, appSecret)
console.log("hash:" + hash)
var signature = hash.toString(CryptoJS.enc.Base64)
console.log("signature:" + signature)

pm.globals.set('AppKey', appKey);
pm.globals.set('Md5', md5);
pm.globals.set("Date", date);
pm.globals.set("Signature", signature);
pm.globals.set("SignatureHeaders", signatureHeaders);
pm.globals.set("Nonce", nonce);

function headersToSign() {
var headers = new Map();
for (var name in request.headers) {
name = name.toLowerCase();
if (!name.startsWith('x-ca-')) {
continue;
}
if (name === "x-ca-signature" || name === "x-ca-signature-headers" || name == "x-ca-key" || name === 'x-ca-nonce') {
continue;
}
var value = request.headers[name];
headers.set(name, value);
}
headers.set('x-ca-key', appKey);
headers.set('x-ca-nonce', nonce);
return headers;
}

function urlToSign() {
var params = new Map();
var contentType = request.headers["content-type"];
if (contentType && contentType.startsWith('application/x-www-form-urlencoded')) {
const formParams = request.data.split("&");
formParams.forEach((p) => {
const ss = p.split('=');
params.set(ss[0], ss[1]);
})
}
const ss = request.url.split('?');
if (ss.length > 1 && ss[1]) {
const queryParams = ss[1].split('&');
queryParams.forEach((p) => {
const ss = p.split('=');
params.set(ss[0], ss[1]);
})
}

var sortedKeys = Array.from(params.keys())
sortedKeys.sort();

var l1 = ss[0].lastIndexOf('/');
var url = ss[0].substring(l1);
var first = true;
var qs
for (var k of sortedKeys) {
var s = k + "=" + params.get(k);
qs = qs ? qs + "&" + s : s;
console.log("key=" + k + " value=" + params.get(k));
}
return qs ? url + "?" + qs : url;
}

function calcMd5() {
var contentType = request.headers["content-type"];
if (request.data && !contentType.startsWith('application/x-www-form-urlencoded')) {
var data = request.data;
var md5 = CryptoJS.MD5(data);
var md5String = md5.toString(CryptoJS.enc.Base64);
console.log("data:" + data + "\nmd5:" + md5String);
return md5String;
} else {
return "";
}
}

function createUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

关于mv 移动文件时出现Argument list too long的解决方案

发表于 2020-09-03

移动所有文件到指定目录

1
mv 需要移动的目录/* 目标目录/

当出现文件过多时报错:Argument list too long

解决方案:

移动文件:

1
find sourcePath/ -name "*.txt"  -exec mv {} targetPath/  \;

or:

1
find sourcePath/ -type f  -exec mv {} targetPath/  \;

查看所有行目录下所有txt文件的行:

1
find sourcePath/ -name "*.txt" |xargs cat |wc -l

只移动前5个文件

1
mv `ls |sed -n 1,5p  /post

只拷贝前5个文件

1
cp -R `ls |sed -n 1,5p /post

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

1…404142…51

乱码三千

android程序员一枚,擅长java,kotlin,python,金融投资,欢迎交流~

505 日志
145 标签
RSS
© 2026 乱码三千
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%