puppeteer(自动化测试和爬虫)

首先puppeteer是一个node库,它提供了一组谷歌官方提供的用来操纵chrome 的api,他有点类似于phantom.js,但是谷歌亲儿子是没法比的。

Puppeteer 核心功能

  1. 利用网页生成PDF、图片
  2. 爬取SPA应用,并生成预渲染内容
  3. 可以从网站抓取内容
  4. 自动化表单提交、UI测试、键盘输入等
  5. 帮你创建一个最新的自动化测试环境(chrome),可以直接在此运行测试用例
  6. 捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题

有了这些功能我们可以考虑做一些事情了,比如上次公司搞一个直播平台的分流,抓取平台的直播图片并存入redis

const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6']; //模拟设备
const redis = require('redis');

(async()=>{
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();

var client = redis.createClient("6379","127.0.0.1");
client.on("error",function(error){
console.log(error);
});

page.setJavaScriptEnabled(true),
//设置UA
await page.emulate(iPhone);
await page.goto('http://baikezhibo.telecomjs.com/webcast/site/entry/join-2ca95de17aef4d12b8ed3c4c4e14879c');
page.click('#enterBtn');
await page.type('#nickNameInput','123', {delay: 100});
await page.type('#nickNameInput','123', {delay: 100});
await page.type('#tokenInput','999999', {delay: 100});
page.click('.submit-btn');
await page.waitFor(100); //这里需要让服务延时一下,否则会出现bug
page.click('.triangle_button');
page.click('.video_img_i');
await page.waitFor(500);
const targetLink = await page.$eval('.doc-widget', e => e.src);
const liu = await page.$eval('.video-widget',e=>e.src);
//console.log(targetLink);
console.log(liu);
//await page.goto(targetLink);

const reg = /^http:\/\/baikezhibo.telecomjs.com\/httpstream\/[a-zA-Z0-9]{32}\/[0-9]{10}_[0-9]{1}\.png$/;
page.on('console', msg =>{
var res=reg.exec(msg.text());
if(res){
console.log(res);
}
//写入redis
client.select('15',function(error){
if(error){
console.log(error);
}else{
client.set('urlLink',res,function(error,res){
if(error){
console.log(error);
}else{
console.log(res);
}
});
}
});

} );
await page.waitFor(1000);
browser.close();
client.end();
})()

AJAX(初识

创建 XMLHttpRequest 对象

var xmlhttp;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
open(method,url,async) 规定请求的类型、URL 以及是否异步处理请求。

  • method:请求的类型;GET 或 POST
  • url:文件在服务器上的位置
  • async:true(异步)或 false(同步)
send(string) 将请求发送到服务器。

  • string:仅用于 POST 请求

例:

xmlhttp.open("GET","demo_get.asp",true);
xmlhttp.send();

AJAX 指的是异步 JavaScript 和 XML(Asynchronous JavaScript and XML)

当使用 async=true 时,请规定在响应处于 onreadystatechange 事件中的就绪状态时执行的函数:

xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();

onreadystatechange 事件
当请求被发送到服务器时,我们需要执行一些基于响应的任务。

每当 readyState 改变时,就会触发 onreadystatechange 事件。

readyState 属性存有 XMLHttpRequest 的状态信息。

onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪

status 200: “OK”

404: 未找到页面

php过滤器(filters)

PHP 过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入。

filter_var() 函数通过指定的过滤器过滤变量。

语法格式:

filter_var(variable, filter, options)
       /*需要过滤的变量*//*使用的过滤器的 ID*//*包含标志/选项的数组*/
Filters函数:
  • filter_var() – 通过一个指定的过滤器来过滤单一的变量
  • filter_var_array() – 通过相同的或不同的过滤器来过滤多个变量
  • filter_input – 获取一个输入变量,并对它进行过滤
  • filter_input_array – 获取多个输入变量,并通过相同的或不同的过滤器对它们进行过滤
Filters:
FILTER_CALLBACK 调用用户自定义函数来过滤数据。
FILTER_SANITIZE_STRING 去除标签,去除或编码特殊字符。
FILTER_SANITIZE_STRIPPED “string” 过滤器的别名。
FILTER_SANITIZE_ENCODED URL-encode 字符串,去除或编码特殊字符。
FILTER_SANITIZE_SPECIAL_CHARS HTML 转义字符 ‘”<>& 以及 ASCII 值小于 32 的字符。
FILTER_SANITIZE_EMAIL 删除所有字符,除了字母、数字以及 !#$%&’*+-/=?^_`{|}~@.[]
FILTER_SANITIZE_URL 删除所有字符,除了字母、数字以及 $-_.+!*'(),{}|\\^~[]`<>#%”;/?:@&=
FILTER_SANITIZE_NUMBER_INT 删除所有字符,除了数字和 +-
FILTER_SANITIZE_NUMBER_FLOAT 删除所有字符,除了数字、+- 以及 .,eE。
FILTER_SANITIZE_MAGIC_QUOTES 应用 addslashes()。
FILTER_UNSAFE_RAW 不进行任何过滤,去除或编码特殊字符。
FILTER_VALIDATE_INT 在指定的范围以整数验证值。
FILTER_VALIDATE_BOOLEAN 如果是 “1”, “true”, “on” 以及 “yes”,则返回 true,如果是 “0”, “false”, “off”, “no” 以及 “”,则返回 false。否则返回 NULL。
FILTER_VALIDATE_FLOAT 以浮点数验证值。
FILTER_VALIDATE_REGEXP 根据 regexp,兼容 Perl 的正则表达式来验证值。
FILTER_VALIDATE_URL 把值作为 URL 来验证。
FILTER_VALIDATE_EMAIL 把值作为 e-mail 来验证。
FILTER_VALIDATE_IP 把值作为 IP 地址来验证。

 

 

php验证

  • 通过使用 htmlspecialchars() 函数能够避免 $_SERVER[“PHP_SELF”] 被利用。

htmlspecialchars() 函数把特殊字符转换为 HTML 实体。这意味着 < 和 > 之类的HTML 字符会被替换为 &lt; 和 &gt; 。这样可防止攻击者通过在表单中注入 HTML 或JavaScript 代码(跨站点脚本攻击)对代码进行利用。

在用户提交该表单时,我们还要做两件事:
通过 PHP trim() 函数)去除用户输入数据中不必要的字符(多余的空格、制表符、换行)
通过 PHP stripslashes() 函数)删除用户输入数据中的反斜杠(\)

<?php
// 定义变量并设置为空值
$name = $email = $gender = $comment = $website = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
  $name = test_input($_POST["name"]);
  $email = test_input($_POST["email"]);
  $website = test_input($_POST["website"]);
  $comment = test_input($_POST["comment"]);
  $gender = test_input($_POST["gender"]);
}

function test_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}
?>

PHP验证Email

$email = test_input($_POST["email"]);
if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email)) {
  $emailErr = "无效的 email 格式!"; 
}

PHP验证url

$website = test_input($_POST["website"]);
if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%
=~_|]/i",$website)) {
  $websiteErr = "无效的 URL"; 
}

老师觉得我毕设内容不丰富.jpg(毕设4)

导师要我拓展系统的内容。可是一个二维码门锁能拓展成什么样呢?没办法,就加一个二维码分享功能吧,虽然这功能也太鸡肋了。

1.写一个save函数

public static void saveMyBitmap(Bitmap bitmap, String path) {

    File f = new File(path);

    FileOutputStream fOut = null;

    try {

        fOut = new FileOutputStream(f);

    } catch (FileNotFoundException e) {

        e.printStackTrace();

        return;

    }

    bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fOut);

    try {

        fOut.flush();

        fOut.close();

    } catch (IOException e) {

        e.printStackTrace();

    }

}

2.获取系统时间来命名图片

SimpleDateFormat sDateFormat    =   new    SimpleDateFormat("yyyy-MM-dd    hh:mm:ss");
Date    curDate    =   new    Date(System.currentTimeMillis());//获取当前时间
String    str    =   sDateFormat.format(curDate);
String imagePath = Environment.getExternalStorageDirectory() + File.separator + str+".jpeg";
saveMyBitmap(qrcode,imagePath);

3.createchooser应用选择器来分享

Uri imageUri = Uri.fromFile(new File(imagePath));
Intent shareIntent =new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent,"分享到:"));

补一补我那拙劣的前端知识(jquery

  •  fadeToggle() 方法可以在 fadeIn() 与 fadeOut() 方法之间进行切换。

语法:$(selector).fadeToggle(speed,callback);

$("button").click(function(){
$("#div1").fadeToggle();
$("#div2").fadeToggle("slow");
$("#div3").fadeToggle(3000);
});
  • jQuery slideToggle() 方法可以在 slideDown() 与 slideUp() 方法之间进行切换。

语法:$(selector).slideToggle(speed,callback);

$("#flip").click(function(){
  $("#panel").slideToggle();
});
  • jQuery animate() 方法用于创建自定义动画。

语法:$(selector).animate({params},speed,callback);
必需的 params 参数定义形成动画的 CSS 属性。

可选的 speed 参数规定效果的时长。它可以取以下值:”slow”、”fast” 或毫秒。

可选的 callback 参数是动画完成后所执行的函数名称。

$("button").click(function(){
  var div=$("div");
  div.animate({height:'300px',opacity:'0.4'},"slow");
  div.animate({width:'300px',opacity:'0.8'},"slow");
  div.animate({height:'100px',opacity:'0.4'},"slow");
  div.animate({width:'100px',opacity:'0.8'},"slow");
});

继续阅读补一补我那拙劣的前端知识(jquery

毕设写完不知道写些什么(android studio初体验?)(毕设3)

1.android studio 的新布局:ConstraintLayout

好用,拖就行了;另外原RelativeLayout中的内容也可以自动转换到ConstraintLayout

2.在实际项目中,一般很少直接访问MySQL数据库,一般情况下会通过http请求将数据传送到服务端,然后在服务端连接mysql数据库。但是,我懒得写一个php的服务端了,所以直接在android中是用jdbc来连接访问数据库了。

使用jdbc需要需赋予项目权限:

在AndroidManifest.xml 中,添加

<uses-permission android:name="android.permission.INTERNET"/>

数据库连接和访问:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Connection conn = openConnection(url,user,pass);


        String sql = "select * from key_value";


        Statement statement = null;
        ResultSet result = null;

        try {
            statement = conn.createStatement();
            result = statement.executeQuery(sql);

            while(result.next()){
            qrstr=result.getString("key");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }  

    }
}).start();

注意:在调用mysql时,需要使用线程。

继续阅读毕设写完不知道写些什么(android studio初体验?)(毕设3)

树莓派二维码识别(毕设2)

树莓派GPIO控制:

树莓派40pin引脚图:

 

控制GPIO

想用python来控制GPIO,最便捷的办法就是使用一些python类库,比如树莓派系统本身集成的RPi.GPIO。本文详细介绍如何使用RPi.GPIO来控制GPIO。

导入RPi.GPIO模块

可以用下面的代码导入RPi.GPIO模块。

import RPi.GPIO as GPIO

引入之后,就可以使用GPIO模块的函数了。如果你想检查模块是否引入成功,也可以这样写:

try:
    import RPi.GPIO as GPIO
except RuntimeError:
    print("引入错误")

针脚编号

在RPi.GPIO中,同时支持树莓派上的两种GPIO引脚编号。第一种编号是BOARD编号,这和树莓派电路板上的物理引脚编号相对应。使用这种编号的好处是,你的硬件将是一直可以使用的,不用担心树莓派的版本问题。因此,在电路板升级后,你不需要重写连接器或代码。

第二种编号是BCM规则,是更底层的工作方式,它和Broadcom的片上系统中信道编号相对应。在使用一个引脚时,你需要查找信道号和物理引脚编号之间的对应规则。对于不同的树莓派版本,编写的脚本文件也可能是无法通用的。

你可以使用下列代码(强制的)指定一种编号规则:

GPIO.setmode(GPIO.BOARD)
  # or
GPIO.setmode(GPIO.BCM)

下面代码将返回被设置的编号规则

mode = GPIO.getmode()

继续阅读树莓派二维码识别(毕设2)

python高级特性

列表生成式:

基本格式:

[x * x for x in array[]]

双层循环:

>>>[m + n for m in 'ABC' for n in 'XYZ']
>>>['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

多变量循环:

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> for k, v in d.items():
...     print(k, '=', v)
...
y = B
x = A
z = C

练习:忽略整数将大写字母换小写

# -*- coding: utf-8 -*-
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [s.lower() for s in L1 if isinstance(s,str)==True]

继续阅读python高级特性

树莓派二维码识别(毕设1)

毕业设计搞了一个带预约功能的二维码门禁系统。

今天就先搞一下二维码的识别和生成,为后续工作做点铺垫。

这里不使用python模块,直接在终端用命令安装依赖环境。

  • sudo apt-get install python-imaging   //图像处理
  • sudo apt-get install zbar-tools              //二维码处理依赖环境
  • sudo apt-get install qrencode               //二维码生成qrencode库

 

我们通过os模块的函数来调用系统命令来实现二维码识别,生成以及图像采集功能。

下面是python代码:

qrcode.py:

#! /usr/bin/env python
#-*- coding: UTF-8 -*-
import os , signal,subprocess

qrstr1="qrcode"
def qrtext(): #generate QRcode text
text=raw_input(u"enter text QRcode:") #input QRcode text
os.system("qrencode -o /home/scf/py-qr-code/createQR/"+qrstr1+".png '"+text+"'") 
#generate QRcode text
print u"qrcode in:"+qrstr1+".png"

def distinguish():
os.system("raspistill -w 320 -h 240 -o /home/scf/py-qr-code/QRimage/image.jpg")
print u"raspistill finished"
#child thread processing QRcode
qrcamera=subprocess.Popen("zbarimg --raw /home/scf/py-qr-code/QRimage/image.jpg",stdout=subprocess.PIPE,shell=True,preexec_fn=os.setsid)
qrcodetext=qrcamera.stdout.readline()
if qrcodetext!="":
print qrcodetext
else:
print u"qrcodetext is empty"
return u"QRcode: "+qrcodetext

继续阅读树莓派二维码识别(毕设1)