-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
python 学习 #110
Comments
"""
### #### ######
### ### # ###
### ### ######
### #### ### ##
### #### ### ##
### ########## ##### ###
i2a creates ASCII art from images right on your terminal.
Usage: i2a [options] [FILE]
Options:
-h --help Show this on screen.
-v --version Show version.
-c --colors Show colored output.
-b --bold Output bold characters
--contrast=<factor> Manually set contrast [default: 1.5].
--alt-chars Use an alternate set of characters.
"""
import subprocess
from colors import *
from PIL import Image, ImageEnhance
from docopt import docopt
__version__ = '1.0'
_ASCII = "@80GCLft1i;:,. "
_ASCII_2 = "Q0RMNWBDHK@$U8&AOkYbZGPXgE4dVhgSqm6pF523yfwCJ#TnuLjz7oeat1[]!?I}*{srlcxvi)><\\)|\"/+=^;,:'_-`. "
def rgb(red, green, blue):
return 16 + (red * 36) + (green * 6) + blue
def set_style(fg=None, bg=None, bold=None):
print(_set_style(fg, bg, bold), end='')
def _set_style(fg=None, bg=None, bold=''):
result = ''
if fg:
result += '\x1b[38;5;%dm' % fg
if bg:
result += '\x1b[48;5;%dm' % bg
if bold:
result += '\x1b[1m'
return result
def reset_color():
print(_reset_color(), end='')
def _reset_color():
return '\x1b[0m'
def print_color(*args, **kwargs):
fg = kwargs.pop('fg', None)
bg = kwargs.pop('bg', None)
bold = kwargs.pop('bold', None)
set_style(fg, bg, bold)
print(*args, **kwargs)
reset_color()
def display_output(arguments):
global _ASCII
if arguments['--alt-chars']:
_ASCII = _ASCII_2
try:
im = Image.open(arguments['FILE'])
except:
raise IOError('Unable to open the file.')
im = im.convert("RGBA")
try:
_HEIGHT, _WIDTH = map(int, subprocess.check_output(['stty', 'size']).split())
except:
_HEIGHT, _WIDTH = 50, 50
aspect_ratio = im.size[0] / im.size[1]
scaled_height = _WIDTH / aspect_ratio
scaled_width = _HEIGHT * aspect_ratio * 2
width = scaled_width
height = scaled_height
if scaled_width > _WIDTH:
width = int(_WIDTH)
height = int(scaled_height / 2)
elif scaled_height > _HEIGHT:
width = int(scaled_width)
height = int(_HEIGHT)
im = im.resize((width,height), resample=Image.ANTIALIAS)
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(float(arguments['--contrast']))
img = im.getdata()
im = im.convert('L')
bg = rgb(0, 0, 0)
fg = rgb(5, 5, 5)
bold = None
if arguments['--bold']:
bold = True
else:
bold = False
row_len = 0
for (count, i) in enumerate(im.getdata()):
ascii_char = _ASCII[int((i / 255.0) * (len(_ASCII) - 1))]
if arguments['--colors']:
color = rgb(int((img[count][0] / 255.0) * 5), int((img[count][1] / 255.0) * 5),int((img[count][2] / 255.0) * 5))
bg = color
fg = rgb(0, 0, 0)
print_color(ascii_char, end='', fg=fg, bg=bg, bold=bold)
row_len += 1
if row_len == width:
row_len = 0
print('')
def main():
arguments = docopt(__doc__, version=__version__)
if arguments['FILE']:
display_output(arguments)
else:
print(__doc__)
if __name__ == '__main__':
main()
from os import path
from wordcloud import WordCloud
import os
d = path.dirname(__file__)
font=os.path.join(os.path.dirname(__file__), "DroidSansFallbackFull.ttf")
font='simhei.ttf'
# Read the whole text.
#text = open(path.join(d, 'constitution.txt')).read()
text = open(u"video.html").read().decode('gbk')
# Generate a word cloud image
wordcloud = WordCloud(font_path=font).generate(text)
# Display the generated image:
# the matplotlib way:
import matplotlib.pyplot as plt
plt.imshow(wordcloud)
plt.axis("off")
# lower max_font_size
wordcloud = WordCloud(font_path=font,max_font_size=40).generate(text)
plt.figure()
plt.imshow(wordcloud)
plt.axis("off")
plt.show() |
https://getman.cn/4e7Pn ffmpeg -i test.mp4 -codec copy -bsf h264_mp4toannexb test.ts >>> sprintf("%15s",'1.2.3')
=> " 1.2.3"
public static function get_client_ip($type = 0)
{
$type = $type ? 1 : 0;
static $ip = NULL;
if ($ip !== NULL) return $ip[$type];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$pos = array_search('unknown',$arr);
if(false !== $pos) unset($arr[$pos]);
$ip = trim($arr[0]);
}elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}elseif (isset($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$long = sprintf("%u",ip2long($ip));
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
return $ip[$type];
}
/**
* 计算集群节点
* @param $room 房间号
* @param array $node 节点数组
*/
public static function calculateNode($room,$num){
if(!empty($room) && !empty($num)){
return crc32(hash('md5',$room)) % $num;
}
return false;
}
/**
* curl多线程请求
* @param $channel
* @param $array
* @param $data
* @param int $timeout
* @return array
*/
public static function multipleThreadsRequest($channel,$array,$data,$timeout = 10){
$res = [];
$mh = curl_multi_init();//创建多个curl语柄
foreach($array as $k=>$url){
$conn[$k]=curl_init($url.'?id='.$channel);
curl_setopt($conn[$k], CURLOPT_TIMEOUT, $timeout);//设置超时时间
curl_setopt($conn[$k], CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($conn[$k], CURLOPT_HEADER, 0);//这里不要header,加块效率
curl_setopt($conn[$k],CURLOPT_RETURNTRANSFER,1);
curl_setopt($conn[$k], CURLOPT_POSTFIELDS, $data);
curl_multi_add_handle ($mh,$conn[$k]);
}
$running = NULL;
do {
usleep(10000);
curl_multi_exec($mh,$running);
} while($running > 0);
foreach ($array as $k => $url) {
$errors = curl_error($conn[$k]);
$res[$k]=curl_multi_getcontent($conn[$k]);//获得返回信息
$header[$k]=curl_getinfo($conn[$k]);//返回头信息
//抛入异常日志记录
if(!empty($errors)){
$header[$k]['errors'] = $errors;
}
curl_close($conn[$k]);//关闭语柄
curl_multi_remove_handle($mh , $conn[$k]); //释放资源
}
curl_multi_close($mh);
return [
'return'=>$res,
'header'=>$header
];
} |
use Illuminate\Http\Request;
public function postLogin($q Request){
// 先校验验证码
$this->validate($q, [
'captcha' => 'required|captchadun',
]);
return response()->json(['code' => '200', 'msg' => 'success'])
}
App\Providers\CaptchaDunServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\CaptchaVerifier;
class CaptchaDunServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot()
{
$this->app['validator']->extend('captchadun', function($attribute, $value, $parameters)
{
return (new CaptchaVerifier(config('services.captcha.CAPTCHA_ID'),config('services.captcha.SECRET_ID'),config('services.captcha.SECRET_KEY')))->verify($value);
});
}
/**
* Register any application services.
*
* This service provider is a great spot to register your various container
* bindings with the application. As you can see, we are registering our
* "Registrar" implementation here. You can add your own bindings too!
*/
public function register()
{
}
}
config/app.php
'providers' => [
'App\Providers\CaptchaDunServiceProvider',
]
App\Services\CaptchaVerifier .php
<?php
namespace App\Services;
/**
* 易盾验证码二次校验SDK http://support.dun.163.com/captcha/api/ http://support.dun.163.com/captcha/demo/#_1
* @author yangweiqiang
*/
class CaptchaVerifier {
const VERSION = 'v2';
const API_TIMEOUT = 5;
const API_URL = 'http://c.dun.163yun.com/api/v2/verify';
/**
* 构造函数
* @param $captcha_id 验证码id
* @param $secret_id 密钥对
* @param $secret_key 密钥对
*/
public function __construct($captcha_id, $secret_id, $secret_key) {
$this->captcha_id = $captcha_id;
$this->secret_id = $secret_id;
$this->secret_key = $secret_key;
}
/**
* 发起二次校验请求
* @param $validate 二次校验数据
* @param $user 用户信息
*/
public function verify($validate, $user = '') {
$params = array();
$params["captchaId"] = $this->captcha_id;
$params["validate"] = $validate;
$params["user"] = $user;
// 公共参数
$params["secretId"] = $this->secret_id;
$params["version"] = self::VERSION;
$params["timestamp"] = sprintf("%d", round(microtime(true)*1000));// time in milliseconds
$params["nonce"] = sprintf("%d", rand()); // random int
$params["signature"] = $this->sign($this->secret_key, $params);
$result = $this->send_http_request($params);\Log::info('captcha',['captcha'=>$result]);
return array_key_exists('result', $result) ? $result['result'] : false;
}
/**
* 计算参数签名
* @param $secret_key 密钥对key
* @param $params 请求参数
*/
private function sign($secret_key, $params){
ksort($params); // 参数排序
$buff="";
foreach($params as $key=>$value){
$buff .=$key;
$buff .=$value;
}
$buff .= $secret_key;
return md5($buff);
}
/**
* 发送http请求
* @param $params 请求参数
*/
private function send_http_request($params){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, self::API_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::API_TIMEOUT);
curl_setopt($ch, CURLOPT_TIMEOUT, self::API_TIMEOUT);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
/*
* Returns TRUE on success or FALSE on failure.
* However, if the CURLOPT_RETURNTRANSFER option is set, it will return the result on success, FALSE on failure.
*/
$result = curl_exec($ch);
// var_dump($result);
if(curl_errno($ch)){
$msg = curl_error($ch);
curl_close($ch);
return array("error"=>500, "msg"=>$msg, "result"=>false);
}else{
curl_close($ch);
return json_decode($result, true);
}
}
}
<meta charset="utf-8"/>
<div id="captcha"></div>
<div class="error-code"></div>
<div class="login">登录</div>
<script src="//code.jquery.com/jquery.js"></script>
<script src="//cstaticdun.126.net/load.min.js"></script>
<script type="text/javascript">
var captchaInstance,captcha;
initCaptcha();
function initCaptcha() {
initNECaptcha({
captchaId: "b7982ef659d64141b7120a6af27e19a0",
element: "#captcha",
//mode: "float",
width: 270,
onReady: function(instance) {
console.log("captchaready");
},
onVerify: function(err, data) {
if (data) {
captcha = data.validate;
}
}
}, function onload(instance) {
captchaInstance = instance;
}, function onerror(err) {
});
}
$('.login').click(function(){
$.ajax({
url: "/login",
type: "POST",
data: {
captcha: captcha
},
success: function(res) {
switch (parseInt(res.code)) {
case 200:
captchaInstance.refresh();
break;
default:
$(".error-code").html("图形码失败");
break;
}
},
error: function(res) {
try {
var resp = $.parseJSON(res.responseText);
if (resp.captcha) {
$(".error-code").html("图形码失败");
return false;
}
} catch (e) {
$(".error-code").html("图形码失败");
}
}
});
});
</script> |
https://blog.lerzen.com/ 书童机器人--果冻陪你聊 整数:例如 100,-200,0 等 需要注意空的集合不能够使用 {} 创建,只能使用 set 函数,因为{} 创建的是一个空的字典 : dict_from_tuple = dict(((1,'Linux'), (2,'Vim'))) coursesdict[5] = 'Bash' for key,value in coursesdict.items(): 字典中也存在 pop(key) 函数,可以返回 key 对应的 value,并将该 key:value 键值对删除 coursesdict.pop(2) 第二个是默认值只被赋值一次,因此如果默认值是任何可变对象时会有所不同,比如列表、字典或大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数 connect('192.168.1.1', 22, 23, 24) 抽象 抽象就是对特定实例抽取共同的特征及行为形成一种抽象类型的过程。 类是一个抽象的概念,而实例是一个具体的对象。比如说狗是一个抽象的概念,因为狗有很多种,而那个正在 wang wang 叫的叫旺财的狗是一个实例。 def get_name(self): Dog 和 Cat 继承了父类 Animal 的初始化方法,get_name 和 set_name 方法,并重写了父类的 make_sound 方法。 class Animal(object):
owner = 'jack'
def __init__(self, name):
self._name = name
@classmethod
def get_owner(cls):
return cls.owner
class Animal(object):
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
def make_sound(self):
pass
@staticmethod
def order_animal_food():
print('ording...')
print('ok')
Animal.order_animal_food()
我们需要谨慎使用 read() 读取整个文件,因为有可能你的系统内存并不足够存储整个文件的内容。当 read() 执行后,再次执行将不会有任何内容的输出。
>>> file = open(filename)
>>> for x in file:
... print(x, end = '')
with open(filename) as file:
count = 0
for line in file:
count += 1
print(line)
print('Lines:', count)
for i, x in enumerate(sys.argv):
if (i == 0):
continue
print(i, x)
d = {'a': 1, 'b': 2, 'c': 3}
{k:v*v for k, v in d.items()}
能被 for 循环访问的都是可迭代的对象,能被 next() 函数获取下一个值的是迭代器。
生成器首先它是一个迭代器,不同的是,生成器只能被迭代一次,因为每次迭代的元素不是像列表元素一样,已经在内存中,而是你每迭代一次,它生成一个元素。
>>> g = (x**x for x in range(1, 4))
>>> g
<generator object <genexpr> at 0x10d1a5af0>
>>> for x in g:
... print(x)
...
1
4
27
和列表解析有点像,只不过使用的是圆括号。不同于列表可以反复迭代,迭代完一次之后再迭代这个生成器,它不会打印元素,也不回报错。
使用生成器有什么好处呢?因为生成器不是把所有元素存在内存,而是动态生成的,所以当你要迭代的对象有非常多的元素时,使用生成器能为你节约很多内存,这是一个内存友好的特性。
>>> def fib(n):
... current = 0
... a, b = 1, 1
... while current < n:
... yield a
... a, b = b, a + b
... current += 1
装饰器本质上是一个函数,它接受一个函数作为参数。
>>> from datetime import datetime
>>> def log(func):
... def decorator(*args, **kwargs):
... print('Function ' + func.__name__ + ' has been called at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
... return func(*args, **kwargs)
... return decorator
...
>>> @log
... def add(x, y):
... return x + y
...
>>> add(1, 2)
Function add has been called at 2017-08-29 13:11:48
3
>>> def add(x, y):
... return x + y
...
>>> add = log(add)
>>> add(1, 2)
Function add has been called at 2017-08-29 13:16:02
3
add 其实已经不再是原来的 add 函数了,它已经变成了log 函数返回的 decorator 函数:
>>> add.__name__
'decorator'
多进程
import os
from multiprocessing import Process
def hello(name):
print('child process: {}'.format(os.getpid()))
print('Hello ' + name)
def main():
# 注意:args 参数要以 tuple 方式传入
p = Process(target=hello, args=('shiyanlou', ))
p.start()
p.join()
print('parent process: {}'.format(os.getpid()))
if __name__ == '__main__':
main()
用 Process 类定义了一个子进程,这个子进程要执行的函数是 hello,传入的参数是 shiyanlou,然后调用 start() 方法,启动子进程,这时候子进程会调用 hello 函数,将 shiyanlou 作为参数传入,打印当前进程 id 和 hello shiyanlou 后返回。 join() 方法表示等待子进程运行结束后继续执行,所以在子进程返回后会继续打印父进程的 id
from multiprocessing import Process, Queue
queue = Queue()
def f1():
queue.put('Hello shiyanlou')
def f2():
data = queue.get()
print(data)
def main():
Process(target=f1).start()
Process(target=f2).start()
if __name__ == '__main__':
main()
import time
from multiprocessing import Process, Value, Lock
def func(val, lock):
for i in range(50):
time.sleep(0.01)
# with lock 语句是对下面语句的简写:
# 使用 acquire() 方法获取锁,release() 方法释放锁
# 多进程无法使用全局变量,multiprocessing 提供的 Value 是一个代理器,
# 可以实现在多进程的共享这个变量
# lock.acquire()
# val.value += 1
# lock.release()
#
with lock:
val.value += 1
if __name__ == '__main__':
v = Value('i', 0)
# 初始化锁
lock = Lock()
procs = [Process(target=func, args=(v, lock)) for i in range(10)]
for p in procs:
p.start()
for p in procs:
p.join()
print(v.value)
用一个进程池打印输出30次范围在0~29之间的数字:
from multiprocessing import Pool
def f(i):
print(i, end=' ')
def main():
# 初始化一个 3 个进程的进程池
pool = Pool(processes=3)
for i in range(30):
# 调用 apply 方法开始处理任务,传入任务处理函数 f,和参数 i
pool.apply(f, (i,))
if __name__ == '__main__':
main()
import threading
def hello(name):
# get_ident() 函数获取当前线程 id
print('child thread: {}'.format(threading.get_ident()))
print('Hello ' + name)
def main():
# 初始化一个线程,参数传递和使用 Process 一样
t = threading.Thread(target=hello, args=('shiyanlou',))
# 启动线程和等待线程结束,和 Process 的接口一样
t.start()
t.join()
print('main thread: {}'.format(threading.get_ident()))
if __name__ == '__main__':
main()
>>> from datetime import datetime
>>> datetime.now().strftime('%Y%m%d %H%M%S')
'20171203 180633'
>>> from collections import OrderedDict
>>> d = OrderedDict()
>>> d['apple'] = 1
>>> d['google'] = 2
>>> from collections import namedtuple
>>> Point = namedtuple('P', ['x', 'y'])
>>> p = Point(10, 12)
>>> p.x
10
>>> p.y
12
from collections import Counter
http://labfile.oss-cn-hangzhou.aliyuncs.com/courses/983/week2/11-22-week2.mp4
export FLASK_APP=app.py
export FLASK_DEBUG=1
flask shell
app = Flask(__name__)
app.config.update({
'SECRET_KEY': 'a random string'
})
app.config.from_pyfile('path/to/config.py')
app.config['SECRET_KEY'] 这样可以获得 SECRET_KEY 的配置值
@app.route('/user/<username>')
def user_index(username):
# 在函数中指名变量名称,这样就能获取到通过路由传入的变量值
return 'Hello {}'.format(username)
@app.route('/post/<int:post_id>')
def show_post(post_id):
return 'Post {}'.format(post_id)
from flask import render_template
@app.route('/user/<username>')
def user_index(username):
return render_template('user_index.html', username=username)
@app.route('/')
def index():
return redirect(url_for('user_index', username='default'))
request.headers.get('User-Agent')
request.headers.get('User-Agent')
@app.errorhandler(404)
def not_found(error):
return render_template('404.html'), 404
from flask import make_response
@app.route('/user/<username>')
def user_index(username):
resp = make_response(render_template('user_index.html', username=username))
resp.set_cookie('username', username)
return resp
app.config['TEMPLATES_AUTO_RELOAD'] = True
每当模板发生改变时,会自动重新渲染模板
{% ... %} 包含的代码是可以被执行的语句,比如循环语句,继承语法;
{{ ... }} 包含的的 Python 对象,用于解析出这些对用的值,经常用于打印内容;
{# ... #} 用于添加注释,这些注释不会被处理,但是也不会输出到 HTML 源码中;
{% if course.is_private %}
<p> course {{course.name}} is private </p>
{% elif course.is_member_course %}
<p> course {{course.name}} is member course </p>
{% else %}
<p> course {{course.name}} is normal course </p>
{% endif %}
{% macro course_item(course, type="bootstrap") %}
<div>
<p> type: {{ type }} </p>
<p> name: {{ course.name }}</p>
<p> user count: {{ course.user_count }}</p>
<p> teacher: {{course.teacher }} </p>
<p> is_private: {{ course.is_private }} </p>
</div>
{% endmacro %}
<div> {{ course_item(course) }} </div>
<p>{{ '=' * 20 }}</p>
<div> {{ course_item(course, type="louplus") }} </div>
来源: 实验楼
链接: https://www.shiyanlou.com/courses/983
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播 |
{% from 'macro.html' import course_item %}
<div> {{ course_item(course) }} </div>
{% extends "base.html" %}
{% from 'macro.html' import course_item %}
{% block header %}
<h1> header </h1>
{% endblock %}
{% block content %}
{{ course_item(course) }}
{% endblock %}
<p> course tag length: {{ course.tags | length }} </p>
添加唯一约束还有一种方式为 alter table user modify email varchar(64) unique;,这种方式实际上是通过修改字段添加唯一索引
有了 ORM 以后可以将 Python 对象映射到数据库中,这样就不用再编写各种 SQL 语句了
$ cd ~/Code
$ sudo pip install virtualenv
$ virtualenv -p /usr/bin/python3.5 env
$ source env/bin/activate
$ pip install sqlalchemy ipython
$ deactivate
In [1]: from sqlalchemy import create_engine
In [2]: engine = create_engine('mysql://root:@localhost/shiyanlou')
In [3]: engine.execute('select * from user').fetchall()
Out[3]: [(1, 'aiden', '[email protected]'), (2, 'lxttx', '[email protected]')]
当在 virtualenv 下安装了包之后,需要先用 deactivate 命令退出 virtualenv 后再重新激活 virtualenv 才可以用这个包。
In [1]: from sqlalchemy import create_engine
In [2]: engine = create_engine('mysql://root:@localhost/shiyanlou')
In [3]: engine.execute('select * from user').fetchall()
Out[3]: [(1, 'aiden', '[email protected]'), (2, 'lxttx', '[email protected]')]
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
In [19]: from sqlalchemy import Column, Integer, String
In [20]: class User(Base):
...: __tablename__ = 'user'
...: id = Column(Integer, primary_key=True)
...: name = Column(String)
...: email = Column(String)
...: def __repr__(self):
...: return "<User(name=%s)>" % self.name
In [27]: User.__table__
Out[27]: Table('user', MetaData(bind=None), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('name', String(), table=<user>), Column('email', String(), table=<user>), schema=None)
In [30]: from sqlalchemy.orm import sessionmaker
In [31]: Session = sessionmaker(bind=engine)
In [32]: session = Session()
In [63]: session.query(User).all()
Out[63]: [<User(name=aiden)>, <User(name=lxttx)>]
In [65]: session.query(User).filter(User.name=='aiden').first()
Out[65]: <User(name=aiden)>
engine = create_engine('mysql://root:@localhost/shiyanlou', echo=True)),则使用 session 查询时,可以看到相应的 SQL 输出:
数据库实例,比如一个 app 使用一个数据库;
collection 文档集合 ,一个数据库包含多个文档集合,类似于 MySQL 中的表;
document 文档,一个文档代表一项数据,类似于 JSON 对象,对应于MySQL 表中的一条记录;
字段:一个文档包含多个字段;
MongoDB 存储的数据可以是无模式的,比如在一个集合中的所有文档不需要有一致的结构。也就是说往同一个表中插入不同的数据时,这些数据之间不必有同样的字段。这和 MySQL 彻底不同,在 MySQL 中创建表时就已经确定了数据项的字段,往其中插入数据时,必须是相同的结构。
MongoDB 存储的文档记录是一个 BSON 对象,类似于 JSON 对象,由键值对组成。比如一条用户记录:
{
name: "Aiden",
age: 30,
email: "[email protected]"
}
每一个文档都有一个 _id 字段,该字段是主键,用于唯一的确定一条记录。如果往 MongoDB 中插入数据时没有指定 _id 字段,那么会自动产生一个 _id 字段,该字段的类型是 ObjectId,长度是 12 个字节。在 MongoDB 文档的字段支持字符串,数字,时间戳等类型。一个文档最大可以达到 16M, 可以存储相当多的数据。
$ mongo
> use shiyanlou
> db.user.insertOne({name: "Aiden", age: 30, email: "[email protected]", addr: ["CD", "SH"]})
{
"acknowledged" : true,
"insertedId" : ObjectId("59a8034064e0acb13483d512")
}
> show databases;
admin 0.000GB
local 0.000GB
shiyanlou 0.000GB
> show collections;
user
db.user.insertMany([
> db.user.find()
{ "_id" : ObjectId("59a8034064e0acb13483d512"), "name" : "Aiden", "age" : 30, "email" : "[email protected]", "addr" : [ "CD", "SH" ] }
db.user.find({name: "jin"})
db.user.find({age: {$gt: 30}})
> db.user.updateOne(
... {name: "Aiden"},
... {$set: {age: 29, addr: ["CD", "SH", "BJ"]}}
... )
db.user.deleteMany({addr: "CD"})
In [2]: from pymongo import MongoClient
In [3]: client = MongoClient('127.0.0.1', 27017)
In [4]: db = client.shiyanlou
In [14]: user = {'name': 'Aiden', 'age': 30, 'addr': ['CD', 'SH', 'BJ']}
In [15]: db.user.insert_one(user)
Out[15]: <pymongo.results.InsertOneResult at 0x10730aa08>
In [17]: db.user.find_one({'name': 'Aiden'})
db.user.update_one({'name': 'Aiden'}, {'$set': {'email': '[email protected]'}})
In [1]: import redis
In [2]: r = redis.StrictRedis(host='127.0.0.1', db=0)
In [3]: r.ping()
Out[3]: True
In [5]: p = r.pubsub()
In [6]: p.subscribe('labreport-channel')
In [7]: for msg in p.listen():
...: print(msg)
...:
{'type': 'subscribe', 'pattern': None, 'channel': b'labreport-channel', 'data': 1}
然后在 redis-cli 客户端中,通过 PUBLISH channel message 指令往频道中发布消息 message:
127.0.0.1:6379> publish labreport-channel "1 msg from redis-cli"
(integer) 1
http://labfile.oss-cn-hangzhou.aliyuncs.com/courses/983/week3/week3.mp4
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-sample1.html
response.css('div#images a::text').extract()
将结果封装为 scrapy 内部的一个 response 对象并注入到 python shell 中,在这个 response 对象上,可以直接使用 scrapy 内置的css 和 xpath 数据提取器 extract 函数执行提取操作
response.css('div#images p::text').extract_first(default='默认值')
response.css('div#images a::attr(href)').extract()
div 中有多个 class 的情况,用 css 提取器可以写为 div[class="class1 class2"]
response.xpath('//div[@id="images"]/a/text()').extract()
response.css('div#images a::text').re('Name: (.+) ')
re() 方法中定义的正则表达式会作用到每个提取到的文本中,只保留正则表达式中的子模式匹配到的内容,也就是 () 内的匹配内容。
import scrapy
class GithubSpider(scrapy.Spider):
name = 'shiyanlou-github'
@property
def start_urls(self):
url_tmpl = 'https:/shiyanlou?page={}&tab=repositories'
return (url_tmpl.format(i) for i in range(1, 5))
def parse(self, response):
for repository in response.css('li.public'):
yield {
'name': repository.xpath('.//a[@itemprop="name codeRepository"]/text()').re_first("\n\s*(.*)"),
'update_time': repository.xpath('.//relative-time/@datetime').extract_first()
}
class ShiyanlouCoursesSpider(scrapy.Spider):
""" 所有 scrapy 爬虫需要写一个 Spider 类,这个类要继承 scrapy.Spider 类。在这个类中定义要请求的网站和链接、如何从返回的网页提取数据等等。
"""
# 爬虫标识符号,在 scrapy 项目中可能会有多个爬虫,name 用于标识每个爬虫,不能相同
name = 'shiyanlou-courses'
def start_requests(self):
""" 需要返回一个可迭代的对象,迭代的元素是 `scrapy.Request` 对象,可迭代对象可以是一个列表或者迭代器,这样 scrapy 就知道有哪些网页需要爬取了。`scrapy.Request` 接受一个 url 参数和一个 callback 参数,url 指明要爬取的网页,callback 是一个回调函数用于处理返回的网页,通常是一个提取数据的 parse 函数。
"""
def parse(self, response):
""" 这个方法作为 `scrapy.Request` 的 callback,在里面编写提取数据的代码。scrapy 中的下载器会下载 `start_reqeusts` 中定义的每个 `Request` 并且结果封装为一个 response 对象传入这个方法。
"""
pass
@property
def start_urls(self):
""" start_urls 需要返回一个可迭代对象,所以,你可以把它写成一个列表、元组或者生成器,这里用的是生成器
"""
url_tmpl = 'https://www.shiyanlou.com/courses/?category=all&course_type=all&fee=all&tag=all&page={}'
return (url_tmpl.format(i) for i in range(1, 23))
def start_requests(self):
# 课程列表页面 url 模版
url_tmpl = 'https://www.shiyanlou.com/courses/?category=all&course_type=all&fee=all&tag=all&page={}'
# 所有要爬取的页面
urls = (url_tmpl.format(i) for i in range(1, 23))
# 返回一个生成器,生成 Request 对象,生成器是可迭代对象
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
# 遍历每个课程的 div.course-body
for course in response.css('div.course-body'):
# 使用 css 语法对每个 course 提取数据
yield {
# 课程名称
'name': course.css('div.course-name::text').extract_first(),
# 课程描述
'description': course.css('div.course-desc::text').extract_first(),
# 课程类型,实验楼的课程有免费,会员,训练营三种,免费课程并没有字样显示,也就是说没有 span.pull-right 这个标签,没有这个标签就代表时免费课程,使用默认值 `免费`就可以了。
'type': course.css('div.course-footer span.pull-right::text').extract_first(default='Free'),
# 注意 // 前面的 .,没有点表示整个文档所有的 div.course-body,有 . 才表示当前迭代的这个 div.course-body
'students': course.xpath('.//span[contains(@class, "pull-left")]/text()[2]').re_first('[^\d]*(\d*)[^\d]*')
}
scrapy runspider shiyanlou_courses_spider.py -o data.json
scrapy startproject shiyanlou
cd /home/shiyanlou/Code/shiyanlou/shiyanlou
scrapy genspider courses shiyanlou.com
import scrapy
class CoursesFollowSpider(scrapy.Spider):
name = 'courses_follow'
start_urls = ['https://shiyanlou.com/courses/63']
def parse(self, response):
yield {
'name': response.xpath('//h4[@class="course-infobox-title"]/span/text()').extract_first(),
'author': response.xpath('//div[@class="mooc-info"]/div[@class="name"]/strong/text()').extract_first()
}
# 不需要 extract 了
for url in response.xpath('//div[@class="sidebox-body course-content"]/a/@href'):
# 不需要构造全 url 了
yield response.follow(url, callback=self.parse)
|
小程序 传图识字 鄙视链条是 用过第三方方案redis集群的 鄙视 用redis本身集群的 鄙视 redis单例 鄙视 没用过的 用过重量级消息队列产品的 鄙视 自实现的 鄙视没用过的 玩过大数据的 鄙视 只做过推荐算法的 鄙视 简单算法的 鄙视 不会算法的 >>> from PIL import Image
>>> im=Image.open('web.jpg')
>>> im.show()
>>> im.save('web.png')
>>> box = (100, 100, 400, 400)
>>> region = im.crop(box)#裁剪
>>> region.save('web.png')
>>> im
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=640x640 at 0x2839C10>
>>> im.show()
>>> out = im.resize((128, 128))
>>> out.show()
>>> out = im.rotate(45)#变形
>>> out.show()
>>> a=im.convert("L")#变色彩http://pillow-zh-cn.readthedocs.io/zh_CN/latest/handbook/tutorial.html
>>> a.show()
>>> from PIL import ImageFilter
>>> b=im.filter(ImageFilter.DETAIL)
>>> b.show() Numpy 使用教程 1.1 实验内容 如果你使用 Python 语言进行科学计算,那么一定会接触到 Numpy。Numpy 是支持 Python 语言的数值计算扩充库,其拥有强大的高维度数组处理与矩阵运算能力。除此之外,Numpy 还内建了大量的函数,方便你快速构建数学模型。 1.2 实验知识点 Numpy 数组 ndarray python2.7 本课程难度为一般,属于初级级别课程,适合具有 Python 基础,并对使用 Numpy 进行科学计算感兴趣的用户。 二、Numpy 多维数组 2.1 ndarray 介绍 在 python 内建对象中,数组有三种形式: list 列表:[1, 2, 3] python 标准类针对数组的处理局限于 1 维,并仅提供少量的功能。 而 Numpy 最核心且最重要的一个特性就是 ndarray 多维数组对象,它区别于 python 的标准类,拥有对高维数组的处理能力,这也是数值计算过程中缺一不可的重要特性。 Numpy 中,ndarray 类具有六个参数,它们分别为: shape:数组的形状。 从 Python 数组结构列表,元组等转换。 在 numpy 中,我们使用 numpy.array 将列表或元组转换为 ndarray 数组。其方法为: numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0) object:列表、元组等。 import numpy as np np.array([[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]]]) 或者是列表和元组: import numpy as np np.array([(1,2),(3,4),(5,6)]) 2.3 arange 方法创建 除了直接使用 array 方法创建 ndarray,在 numpy 中还有一些方法可以创建一些有规律性的多维数。首先,我们来看一看 arange()。arange() 的功能是在给定区间内创建一系列均匀间隔的值。方法如下: numpy.arange(start, stop, step, dtype=None) 举个例子: import numpy as np 在区间 [3, 7) 中以 0.5 为步长新建数组np.arange(3, 7, 0.5, dtype='float32') 2.4 linspace 方法创建 linspace方法也可以像arange方法一样,创建数值有规律的数组。linspace 用于在指定的区间内返回间隔均匀的值。其方法如下: numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) import numpy as np np.linspace(0, 10, 10, endpoint=True) 2.5 ones 方法创建 numpy.ones 用于快速创建数值全部为 1 的多维数组。其方法如下: numpy.ones(shape, dtype=None, order='C') shape:用于指定数组形状,例如(1, 2)或 3。 import numpy as np np.ones((2,3)) 2.6 zeros 方法创建 zeros 方法和上面的 ones 方法非常相似,不同的地方在于,这里全部填充为 0。zeros 方法和 ones 是一致的。 numpy.zeros(shape, dtype=None, order='C') shape:用于指定数组形状,例如(1, 2)或3。 import numpy as np np.zeros((3,2)) 2.7 eye 方法创建 numpy.eye 用于创建一个二维数组,其特点是k 对角线上的值为 1,其余值全部为0。方法如下: numpy.eye(N, M=None, k=0, dtype=<type 'float'>) N:输出数组的行数。 import numpy as np np.eye(5, 4, 3) 2.8 从已知数据创建 我们还可以从已知数据文件、函数中创建 ndarray。numpy 提供了下面 5 个方法: frombuffer(buffer):将缓冲区转换为 1 维数组。 import numpy as np np.fromfunction(lambda a, b: a + b, (5, 4)) 三、ndarray 数组属性 首先,我们创建一个 ndarray 数组,这里还是沿用本章节开头的例子。 import numpy as np a = np.array([[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]],[[1, 2, 3],[1, 2, 3],[1, 2, 3]]]) ndarray 多维数组支持下面这些属性: 3.1 ndarray.T ndarray.T用于数组的转置,与 .transpose() 相同。 import numpy as np a.T 3.2 ndarray.dtype ndarray.dtype 用来输出数组包含元素的数据类型。 import numpy as np a.dtype 3.3ndarray.imag ndarray.imag 用来输出数组包含元素的虚部。 import numpy as np a.imag 3.4ndarray.real ndarray.real用来输出数组包含元素的实部。 import numpy as np a.real 3.5 ndarray.size ndarray.size用来输出数组中的总包含元素数。 import numpy as np a.size 3.6ndarray.itemsize ndarray.itemsize输出一个数组元素的字节数。 import numpy as np a.itemsize 3.7 ndarray.nbytes ndarray.nbytes用来输出数组的元素总字节数。 import numpy as np a.nbytes 3.8 ndarray.ndim ndarray.ndim用来输出数组尺寸。 import numpy as np a.ndim 3.9 ndarray.shape ndarray.shape用来输出数组维数组. import numpy as np a.shape 3.10 ndarray.strides ndarray.strides用来遍历数组时,输出每个维度中步进的字节数组。 import numpy as np a.strides |
二、Numpy 数组的基本操作 上一个章节,我们了解了如何利用 numpy 创建各式各样的 ndarray。本章节,我们将利用学会针对 ndarray 的各种花式操作技巧。 2.1 重设形状 reshape 可以在不改变数组数据的同时,改变数组的形状。其中,numpy.reshape() 等效于 ndarray.reshape()。reshape 方法非常简单: numpy.reshape(a, newshape) 举个例子: import numpy as np np.arange(10).reshape((5, 2)) 2.2 数组展开 ravel 的目的是将任意形状的数组扁平化,变为 1 维数组。ravel 方法如下: numpy.ravel(a, order='C') 示例: import numpy as np a = np.arange(10).reshape((2, 5)) np.ravel(a) 2.3 轴移动 moveaxis 可以将数组的轴移动到新的位置。其方法如下: numpy.moveaxis(a, source, destination) a:数组。 import numpy as np a = np.ones((1, 2, 3)) np.moveaxis(a, 0, -1) 你可能没有看明白是什么意思,我们可以输出二者的 shape属性: 2.4 轴交换 和 moveaxis 不同的是,swapaxes 可以用来交换数组的轴。其方法如下: numpy.swapaxes(a, axis1, axis2) a:数组。 import numpy as np a = np.ones((1, 4, 3)) 2.5 数组转置 transpose 类似于矩阵的转置,它可以将 2 维数组的横轴和纵轴交换。其方法如下: numpy.transpose(a, axes=None) a:数组。 import numpy as np a = np.arange(4).reshape(2,2) 2.6 维度改变 atleast_xd 支持将输入数据直接视为 x维。这里的 x 可以表示:1,2,3。方法分别维: numpy.atleast_1d() import numpy as np np.atleast_1d([1]) 2.7 类型转变 在 numpy 中,还有一系列以 as 开头的方法,它们可以将特定输入转换为数组,亦可将数组转换为矩阵、标量,ndarray 等。如下: asarray(a,dtype,order):将特定输入转换为数组。 import numpy as np a = np.arange(4).reshape(2,2) 2.8 数组连接 concatenate 可以将多个数组沿指定轴连接在一起。其方法为: numpy.concatenate((a1, a2, ...), axis=0) (a1, a2, ...):需要连接的数组。 import numpy as np a = np.array([[1, 2], [3, 4], [5, 6]]) np.concatenate((a, b, c), axis=0) 这里,我们可以尝试沿着横轴连接。但要保证连接处的维数一致,所以这里用到了 .T 转置。 a = np.array([[1, 2], [3, 4], [5, 6]]) np.concatenate((a, b.T), axis=1) 2.9 数组堆叠 在 numpy 中,还有一系列以 as 开头的方法,它们可以将特定输入转换为数组,亦可将数组转换为矩阵、标量,ndarray 等。如下: stack(arrays,axis):沿着新轴连接数组的序列。 import numpy as np a = np.array([1, 2, 3]) 当然,也可以横着堆叠。 np.stack((a, b), axis=-1) 2.10 拆分 split 及与之相似的一系列方法主要是用于数组的拆分,列举如下: split(ary,indices_or_sections,axis):将数组拆分为多个子数组。 import numpy as np a = np.arange(10) 除了 1 维数组,更高维度也是可以直接拆分的。例如,我们可以将下面的数组按行拆分为 2。 import numpy as np a = np.arange(10).reshape(2,5) numpy 中还有针对数组元素添加或移除的一些方法。 2.11 删除 delete(arr,obj,axis):沿特定轴删除数组中的子数组。 import numpy as np a = np.arange(12).reshape(3,4) 当然,你也可以沿着纵轴,将第三行删除。 np.delete(a, 2, 0) 2.12 数组插入 insert(arr,obj,values,axis):依据索引在特定轴之前插入值。 import numpy as np a = np.arange(12).reshape(3,4) np.insert(a, 2, b, 0) 2.13 附加 append(arr,values,axis):将值附加到数组的末尾,并返回 1 维数组。 import numpy as np a = np.arange(6).reshape(2,3) np.append(a, b) 2.14 重设尺寸 resize(a,new_shape):对数组尺寸进行重新设定。 import numpy as np a = np.arange(10) 你可能会纳闷了,这个 resize 看起来和上面的 reshape 一样呢,都是改变数组原有的形状。 其实,它们是有区别的,区别在于对原数组的影响。reshape 在改变形状时,不会影响原数组,相当于对原数组做了一份拷贝。而 resize 则是对原数组执行操作。 2.15 翻转数组 在 numpy 中,我们还可以对数组进行翻转操作: fliplr(m):左右翻转数组。 import numpy as np a = np.arange(16).reshape(4,4) 三、Numpy 随机抽样 Numpy 的随机抽样功能非常强大,主要由 numpy.random 模块完成。 首先,我们需要了解如何使用 numpy 也就是生成一些满足基本需求的随机数据。主要由以下一些方法完成: 3.1 numpy.random.rand numpy.random.rand(d0, d1, ..., dn) 方法的作用为:指定一个数组,并使用 [0, 1) 区间随机数据填充,这些数据均匀分布。 import numpy as np np.random.rand(2,5) 3.2 numpy.random.randn numpy.random.randn(d0, d1, ..., dn) 与 numpy.random.rand(d0, d1, ..., dn) 的区别在于,返回的随机数据符合标准正太分布。 import numpy as np np.random.randn(1,10) 3.3 numpy.random.randint randint(low, high, size, dtype) 方法将会生成 [low, high) 的随机整数。注意这是一个半开半闭区间。 import numpy as np np.random.randint(2,5,10) 3.4 numpy.random.random_integers random_integers(low, high, size) 方法将会生成 [low, high] 的 np.int 类型随机整数。注意这是一个闭区间。 import numpy as np np.random.random_integers(2,5,10) 3.5 numpy.random.random_sample random_sample(size) 方法将会在 [0, 1) 区间内生成指定 size 的随机浮点数。 import numpy as np np.random.random_sample([10]) 与 numpy.random.random_sample 类似的方法还有: numpy.random.random([size]) 3.6 numpy.random.choice choice(a, size, replace, p) 方法将会给定的 1 维数组里生成随机数。 import numpy as np np.random.choice(10,5) 3.7 概率密度分布 除了上面介绍的 6 中随机数生成方法,numpy 还提供了大量的满足特定概率密度分布的样本生成方法。它们的使用方法和上面非常相似,这里就不再一一介绍了。列举如下: numpy.random.beta(a,b,size):从 Beta 分布中生成随机数。 |
2.1 三角函数 首先, 看一看 numpy 提供的三角函数功能。这些方法有: numpy.sin(x):三角正弦。 import numpy as np np.rad2deg(np.pi) 这些函数非常简单,就不再一一举例了。 2.2 双曲函数 在数学中,双曲函数是一类与常见的三角函数类似的函数。双曲函数经常出现于某些重要的线性微分方程的解中,使用 numpy 计算它们的方法为: numpy.sinh(x):双曲正弦。 数值修约, 又称数字修约, 是指在进行具体的数字运算前, 按照一定的规则确定一致的位数, 然后舍去某些数字后面多余的尾数的过程[via. 维基百科]。比如, 我们常听到的「4 舍 5 入」就属于数值修约中的一种。 numpy.around(a):平均到给定的小数位数。
下面这些方法用于数组内元素或数组间进行求和、求积以及进行差分。 numpy.prod(a, axis, dtype, keepdims):返回指定轴上的数组元素的乘积。
如果你需要进行指数或者对数求解,可以用到以下这些方法。 numpy.exp(x):计算输入数组中所有元素的指数。 当然,numpy 也提供了一些用于算术运算的方法,使用起来会比 python 提供的运算符灵活一些,主要是可以直接针对数组。 numpy.add(x1, x2):对应元素相加。
2.7 矩阵和向量积 求解向量、矩阵、张量的点积等同样是 numpy 非常强大的地方。 numpy.dot(a,b):求解两个数组的点积。 除了上面这些归好类别的方法,numpy 中还有一些用于数学运算的方法,归纳如下: numpy.angle(z, deg):返回复参数的角度。 上面,我们分为 8 个类别,介绍了 numpy 中常用到的数学函数。这些方法让复杂的计算过程表达更为简单。除此之外,numpy 中还包含一些代数运算的方法,尤其是涉及到矩阵的计算方法,求解特征值、特征向量、逆矩阵等,非常方便。 numpy.linalg.cholesky(a):Cholesky 分解。 我们可以通过索引值(从 0 开始)来访问 Ndarray 中的特定位置元素。Numpy 中的索引和 python 对 list 索引的方式非常相似,但又有所不同。我们一起来看一下: 首先是,一维数据索引:
获取索引值为 1 的数据
分别获取索引值为 1,2,3 的数据
获取第 2 行,第 3 列的数据
创建一个数据相同的 list
按照上面的方法获取第 2 行,第 3 列的数据,报错。
python 中 list 索引 2 维数据的方法
索引
那么,三维数据呢?
索引
2.2 数组切片 Numpy 里面针对Ndarray的数组切片和 python 里的list 切片操作是一样的。其语法为: Ndarray[start:stop:step]
先取第 3,4 列(第一个维度),再取第 1,2,3 行(第二个维度)。
按步长为 2 取所有列和所有行的数据。
2.3 索引与切片区别 你可能有点疑问,上面的索引和切片怎么看起来这么相似呢? 它们的语法的确很相似,但实际上有区别:
三、排序、搜索、计数 最后,再介绍几个 numpy 针对数组元素的使用方法,分别是排序、搜索和计数。 3.1 排序 我们可以使用 numpy.sort方法对多维数组元素进行排序。其方法为: numpy.sort(a, axis=-1, kind='quicksort', order=None) a:数组。
numpy.lexsort(keys ,axis):使用多个键进行间接排序。 除了排序,我们可以通过下面这些方法对数组中元素进行搜索和计数。列举如下: argmax(a ,axis,out):返回数组中指定轴的最大值的索引。
|
一维数据 Series Series 是 Pandas 中最基本的 1 维数据形式。其可以储存整数、浮点数、字符串等形式的数据。Series 的新建方法如下: s = pandas.Series(data, index=index) 3.1 字典 -> Series 下面,我们将把不同类型的数据转换为为 Series。首先是字典类型。 import pandas as pd d = {'a' : 10, 'b' : 20, 'c' : 30} 这里,数据值是 10, 20, 30,索引为 a, b, c 。我们可以直接通过 index= 参数来设置新的索引。 import pandas as pd s = pd.Series(d, index=['b', 'c', 'd', 'a']) 你会发现,pandas 会自动匹配人为设定的索引值和字典转换过来的索引值。而当索引无对应值时,会显示为 NaN 缺失值。 3.2 ndarray -> Series ndarray 是著名数值计算包 numpy 中的多维数组。我们也可以将 ndarray 直接转换为 Series。 import pandas as pd data = np.random.randn(5) # 一维随机数 s = pd.Series(data, index) 上面的两个例子中,我们都指定了 index 的值。而当我们非人为指定索引值时,Pandas 会默认从 0 开始设置索引值。 s = pd.Series(data) 当我们需要从一维数据 Series 中返回某一个值时,可以直接通过索引完成。 import pandas as pd data = np.random.randn(5) # 一维随机数 s = pd.Series(data, index) 除此之外,Series 是可以直接进行运算的。例如: import pandas as pd data = np.random.randn(5) # 一维随机数 s = pd.Series(data, index) 四、二维数据 DataFrame DataFrame 是 Pandas 中最为常见、最重要且使用频率最高的数据结构。你可以想到它箱型为电子表格或 SQL 表具有的结构。DataFrame 可以被看成是以 Series 组成的字典。它和 Series 的区别在于,不但具有行索引,且具有列索引。 DataFrame 可以用于储存多种类型的输入: 一维数组、列表、字典或者 Series 字典。 import pandas as pd 带 Series 的字典d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),'two' : pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])} df = pd.DataFrame(d) # 新建 DataFrame 我们可以看到,这里的行索引为 a, b, c, d ,而列索引为 one, two。 4.2 ndarrays 或 lists 字典 -> DataFrame import pandas as pd 列表构成的字典d = {'one' : [1, 2, 3, 4], 'two' : [4, 3, 2, 1]} df1 = pd.DataFrame(d) # 未指定索引 print df1 注意观察它们之间的不同。 4.3 带字典的列表 -> DataFrame import pandas as pd 带字典的列表d = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}] df = pd.DataFrame(d) print df 4.4 DataFrame.from_ 方法 pandas 的 DataFrame 下面还有 4 个以 from_ 开头的方法,这也可以用来创建 Dataframe。 例如: import pandas as pd d = [('A', [1, 2, 3]), ('B', [4, 5, 6])] df = pd.DataFrame.from_items(d, orient='index', columns=c) print df 4.5 列选择,添加,删除 接下来,我们延续上面的 4.4 里面的数据来演示。 在一维数据结构 Series 中,我们用 df['标签'] 来选择行。而到了二维数据 DataFrame 中,df['标签'] 表示选择列了。例如: print df['one'] 删除列的方法为 df.pop('列索引名'),例如: df.pop('one') 添加列的方法未 df.insert(添加列位置索引序号, '添加列名', 数值),例如: df.insert(3, 'four', [10, 20]) 五、三维数据 Panel Panel 是 Pandas 中使用频率较低的一种数据结构,但它是三维数据的重要容器。 5.1 面板数据 Panel data 又称面板数据,它是计量经济学中派生出来的一个概念。在计量经济学中,数据大致可分为三类:截面数据,时间序列数据,以及面板数据。而面板数据即是截面数据与时间序列数据综合起来的一种数据类型。 简单来讲,截面数据指在某一时间点收集的不同对象的数据。而时间序列数据是指同一对象在不同时间点所对应的数据集合。 这里引用一个城市和 GDP 关系的示例来解释上面的三个概念(面板数据): 截面数据: 例如城市:北京、上海、重庆、天津在某一年的 GDP 分别为10、11、9、8(单位亿元)。 例如:2000、2001、2002、2003、2004 各年的北京市 GDP 分别为8、9、10、11、12(单位亿元)。 2000、2001、2002、2003、2004 各年中国所有直辖市的 GDP 分别为(单位亿元): 北京市分别为 8、9、10、11、12; 上海市分别为 9、10、11、12、13; 天津市分别为 5、6、7、8、9; 重庆市分别为 7、8、9、10、11。 在 Pandas 中,Panel 主要由三个要素构成: items: 每个项目(item)对应于内部包含的 DataFrame。 import pandas as pd wp = pd.Panel(np.random.randn(2, 5, 4), items=['Item1', 'Item2'], major_axis=pd.date_range('1/1/2000', periods=5), minor_axis=['A', 'B', 'C', 'D']) print wp 我们可以看到,wp 由 2 个项目、5 个主要轴和 4 个次要轴组成。其中,主要轴由 2000-01-01 到 2000-01-05 这 5 天组成的时间序列,次轴从 A 到 D。 你可以输出 Item1 看一看。 print wp['Item1'] 再看一看 Item2。 print wp['Item2] 可以看到,这两个 Dataframe 的行索引及列索引是一致的。由于数据是随机生成的,所以不一致。 5.2 Panel 的未来 由于 Panel 在 Pandas 中的使用频率远低于 Series 和 DataFrame,所以 Pandas 决定在未来的版本中将 Panel 移除,转而使用 MultiIndex DataFrame 来表示多维数据结构。 这里,可以用到 Panel.to_frame() 输出多维数据结构。就拿上面的例子继续: print wp.to_frame() Pandas 支持大部分常见数据文件读取与存储。一般清楚下,读取文件的方法以 pd.read_ 开头,而写入文件的方法以 pd.to_ 开头。详细的表格如下。 拿刚刚下载好的数据文件举例,如果没有下载,请看 1.5 小节。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 可以看到,文件已经读取出来了。由于列数太多,所以分段显示了。输出的最下方会有一个行数和列数的统计。这里是 319 行 X 7 列。 我们可以发现,由 pandas 读取的文件就已经是 DataFrame 结构了。上面演示了 csv 文件的读取,其余格式的文件也很相似。 不过,很多时候我们拿到手的数据是像 los_census.txt 文件样式的数据,如下图所示。 import pandas as pd df = pd.read_table("los_census.txt") #读取 txt 文件 其实 los_census.txt 也就是 los_census.csv 文件,因为 csv 文件又叫逗号分隔符文件,数据之间采用逗号分割。 那么,我们怎样将这种文件转换为 DataFrame 结构的数据呢?这里就要使用到读取方法中提供的一些参数了,例如 sep[] 分隔符参数。 import pandas as pd df = pd.read_table("los_census.txt", sep=',') #读取 txt 文件 除了 sep,读取文件时常用的参数还有: header=,用来选择将第几行作为列索引名称。 import pandas as pd df = pd.read_csv("los_census.csv", header=1 ) #将第二行作为列索引名称。 import pandas as pd df = pd.read_csv("los_census.csv", names=['A', 'B', 'C', 'D', 'E', 'F', 'G']) #自定义列索引名称。 好了,说了这么久的读取文件,再说一说存储文件。存储文件的方法也很简单。比如我们将 los_census.csv 文件,存储为 json 格式的文件。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 df.to_json("1.json") # 将其存储为 json 格式文件 当然,你也可以通过 to_excel("1.xlsx") 储存为 Excel 默认支持的 .xlsx 格式。只是,需要注意在线环境会报错。这时候需要再补充安装 openpyxl 包就好了: sudo pip install openpyxl 有些时候,我们读取的文件很大。如果全部输出预览这些文件,既不美观,又很耗时。还好,Pandas 提供了 head() 和 tail() 方法,它可以帮助我们只预览一小块数据。 顾名思义,head() 方法就是从数据集开头预览,不带参数默认显示头部的 5 条数据,你也可以自定义显示条数。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.head() # 默认显示前 5 条 tail() 方法就是从数据集尾部开始显示了,同样默认 5 条,可自定义。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.tail() # 默认显示后 5 条 2.3 统计方法 Pandas 提供了几个统计和描述性方法,方便你从宏观的角度去了解数据集。
describe() 相当于对数据集进行概览,会输出该数据集的计数、最大值、最小值等。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.describe() 例如上面,针对一个 DataFrame 会对每一列的数据单独统计。
idxmin() 和 idxmax() 会计算最小、最大值对应的索引标签。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.idxmin()
count() 用于统计非空数据的数量。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.count() 4.value_counts() value_counts() 仅仅针对 Series,它会计算每一个值对应的数量统计。 import pandas as pd s = pd.Series(np.random.randint(0, 9, size=100)) # 生成一个 Series,并在 0-9 之间生成 100 个随机值。 print s 2.4 计算方法 除了统计类的方法,Pandas 还提供了很多计算类的方法。
sum() 用于计算数值数据的总和。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.sum()
mean() 用于计算数值数据的平均值。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.mean()
median() 用于计算数值数据的算术中值。 import pandas as pd df = pd.read_csv("los_census.csv") #读取 csv 文件 print df.median() 除此之外,剩下的一些常见计算方法如下表所示。 2.5 标签对齐 索引标签是 Pandas 中非常重要的特性,有些时候,由于数据的缺失等各种因素导致标签错位的现象,或者想匹配新的标签。于是 Pandas 提供了索引标签对齐的方法 reindex()。 reindex() 主要有三个作用: 重新排序现有数据以匹配新的一组标签。 s = pd.Series(data=[1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e']) print s 我们可以看到,重新排列的数据中,原有索引对应的数据能自动匹配,而新索引缺失的数据通过 NaN 补全。 当然,对于 DataFrame 类型的数据也是一样的。 import pandas as pd df = pd.DataFrame(data={'one': [1, 2, 3], 'two': [4, 5, 6], 'three': [7, 8, 9]}, index=['a', 'b', 'c']) print df print df.reindex(index=['b', 'c', 'a'], columns=['three', 'two', 'one']) 你甚至还可以将上面 Series 的数据按照下面的 DataFrame 的索引序列对齐。 print s.reindex(df.index) 2.6 排序 既然是数据处理,就少不了排序这一常用的操作。在 Pandas 中,排序拥有很多「姿势」,下面就一起来看一看。
首先是按照索引排序,其方法为Series.sort_index()或者是DataFrame.sort_index()。 import pandas as pd df = pd.DataFrame(data={'one': [1, 2, 3], 'two': [4, 5, 6], 'three': [7, 8, 9], 'four': [10, 11, 12]}, index=['a', 'c', 'b']) print df 下面按索引对行重新排序: print df.sort_index() 或者添加参数,进行倒序排列: print df.sort_index(ascending=False)
第二种是按照数值排序,其方法为Series.sort_values()或者是DataFrame.sort_values()。举个例子: import pandas as pd df = pd.DataFrame(data={'one': [1, 2, 3, 7], 'two': [4, 5, 6, 9], 'three': [7, 8, 9, 2], 'four': [10, 11, 12, 5]}, index=['a', 'c', 'b','d']) print df 将第三列按照从小到大排序: print df.sort_values(by='three') 也可以同时按照两列: print df[['one', 'two', 'three', 'four']].sort_values(by=['one','two']) |
基于索引数字选择 当我们新建一个 DataFrame 之后,如果未自己指定行索引或者列对应的标签,那么 Pandas 会默认从 0 开始以数字的形式作为行索引,并以数据集的第一行作为列对应的标签。其实,这里的「列」也有数字索引,默认也是从 0 开始,只是未显示出来。 所以,我们首先可以基于数字索引对数据集进行选择。这里用到的 Pandas 中的 .iloc 方法。该方法可以接受的类型有: 整数。例如:5 import pandas as pd df = pd.read_csv("los_census.csv") print df.head() 首先,我们可以选择前 3 行数据。这和 python 或者 numpy 里面的切片很相似。 print df.iloc[:3] 我们还可以选择特定的一行。 print df.iloc[5] 那么选择多行是不是 print df.iloc[1, 3, 5] 这样呢?答案是错误的。df.iloc[] 的 [[行],[列]] 里面可以同时接受行和列的位置,如果你直接键入 df.iloc[1, 3, 5] 就会报错。 所以,很简单。如果你想要选择 1,3,5 行,可以这样做。 print df.iloc[[1, 3, 5]] 选择行学会以后,选择列就应该能想到怎么办了。你可以先暂停浏览下面的内容,自己试一试。 例如,我们要选择第 2-4 列。 print df.iloc[:, 1:4] 这里选择 2-4 列,输入的却是 1:4。这和 python 或者 numpy 里面的切片操作非常相似。 既然我们能定位行和列,那么只需要组合起来,我们就可以选择数据集中的任何一块数据了。 2.2 基于标签名称选择 除了根据数字索引选择,我们还可以直接根据标签对应的名称选择。这里用到的方法和上面的 iloc 很相似,少了个 i 为 df.loc[]。 df.loc[] 可以接受的类型有: 单个标签。例如:2 或 'a',这里的 2 指的是标签而不是索引位置。 import pandas as pd df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE')) print df 先选择前 3 行: print df.loc['a':'c'] 再选择 1,3,5 行: print df.loc[['a', 'c', 'd']] 然后,选择 2-4 列: print df.loc[:, 'B':'D'] 最后,选择 1,3 行和 C 后面的列: print df.loc[['a','c'], 'C':] 2.3 数据随机取样 上面,的 .iloc 和 .loc 可用于精准定位数据块。而 Pandas 同样也提供了随机取样的方法,用于满足各种情况。随机取样用 .sample() 完成,下面我们就演示一下它的用法。 首先,看一看 Series 数据结构。 import pandas as pd s = pd.Series([0,1,2,3,4,5,6,7,8,9]) print s.sample() 我们可以看到,默认情况下 .sample() 返回了一个数值。注意,前面的 2 是数字索引,后面的 2 才是值。 我们可以通过 n= 参数,设定返回值的数量。 print s.sample(n=5) 同样也可以用 frac= 参数设定返回数量的比例。 print s.sample(frac=.6) # 返回 60% 的数值 对应 DataFrame 而言,过程也很相似,只是需要选择坐标轴。举个例子: import pandas as pd df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE')) print df 默认会返回行,如果要随机返回 3 列。需要添加 axis= 参数。 print df.sample(n=3, axis=1) 2.4 条件语句选择 数据选择的时候,我们还可以加入一些条件语句,从而达到对数据筛选的目的。这个过程和 numpy 里面的效果很相似。我们先举一个 Series 的例子: import pandas as pd s = pd.Series(range(-5, 5)) print s 对于 DataFrame 也是相似的。 import pandas as pd df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE')) print df 2.5 where() 方法选择 接下来,再介绍一种通过 where() 方法进行数据选择得方法。DataFrame 和 Series 都带有 where(),可以通过一些判断句来选择数据。举个例子: import pandas as pd df = pd.DataFrame(np.random.randn(6,5),index=list('abcdef'),columns=list('ABCDE')) print df 你也可以对判断条件以外得值重新替代,例如这里将非负值全部变号为负值。 print df.where(df < 0, -df) # 筛选负值并将正值变号 故,where() 实际上期待了匹配和替换得效果。我们可以借助该方法实现对数据的自由设定。 2.6 query() 方法选择 针对数据变换和筛选的方法还很多,除了上面的提到的,Pandas 0.13 之后的版本中增加了 query() 实验性方法,该方法也可以被用来选择数据。 query() 是 DataFrame 具有的方法,你可以通过一个比较语句对满足行列条件的值进行选择,举个例子: import pandas as pd df = pd.DataFrame(np.random.rand(10, 5), columns=list('abcde')) print df 当然,在没有 query() 之前,我们也是可以通过前面提到的条件语句选择。 print df[(df.a < df.b) & (df.b < df.c)] 结果虽然一致,但是 query() 语句的确要简洁和自然很多。query() 包含很多内容,非常强大。你可以通过官方文档了解,这里就不再赘述了。 二、认识缺失值 在真实的生产环境中,我们需要处理的数据文件往往没有想象中的那么美好。其中,很大几率会遇到的情况就是缺失值。 2.1 什么是缺失值? 缺失值主要是指数据丢失的现象,也就是数据集中的某一块数据不存在。除此之外、存在但明显不正确的数据也被归为缺失值一类。例如,在一个时间序列数据集中,某一段数据突然发生了时间流错乱,那么这一小块数据就是毫无意义的,可以被归为缺失值。 当然,除了原始数据集就已经存在缺失值以外。当我们用到前面章节中的提到的索引对齐(reindex())的方法时,也容易人为导致缺失值的产生。举个例子: 首先,我们生成一个 DataFrame。 import pandas as pd df = pd.DataFrame(np.random.rand(5, 5), index=list('cafed'),columns=list('ABCDE')) print df 然后,我们使用 `reindex() 完成索引对齐。 print df.reindex(list('abcde')) 由于原始数据集中,没有索引 b,所以对齐之后,b 后面全部为缺失值,也就造成了数据缺失。 2.2 检测缺失值 Pandas 为了更方便地检测缺失值,将不同类型数据的缺失均采用 NaN 标记。这里的 NaN 代表 Not a Number,它仅仅是作为一个标记。例外是,在时间序列里,时间戳的丢失采用 NaT 标记。 Pandas 中用于检测缺失值主要用到两个方法,分别是:isnull() 和 notnull(),故名思意就是「是缺失值」和「不是缺失值」。默认会返回布尔值用于判断。 下面,演示一下这两个方法的作用,我们这里沿用上面进行索引对齐后的数据。 df2 = df.reindex(list('abcde')) df2.isnull() 然后,我们来看一下对时间序列缺失值的检测,对上面的 df2 数据集进行稍微修改。 插入 T 列,并打上时间戳df2.insert(value=pd.Timestamp('2017-10-1'),loc=0,column='T') 将 T 列的 1,3,5 行置为缺失值df2.loc[['a','c','e'],['T']] = np.nan df2.isnull() 三、填充和清除缺失值 上面已经对缺省值的产生、检测进行了介绍。那么,我们面对缺失值时,到底有哪些实质性的措施呢?接下来,就来看一看如何完成对缺失值填充和清除。 填充和清除都是两个极端。如果你感觉有必要保留缺失值所在的列或行,那么就需要对缺失值进行填充。如果没有必要保留,就可以选择清除缺失值。 Pandas 中,填充缺失的方法为 fillna(),清除为 dropna()。 3.1 填充缺失值 fillna() 首先,我们看一看 fillna() 的使用方法。重新打开一个 ipython 终端,我们生成和上面相似的数据。 import pandas as pd df = pd.DataFrame(np.random.rand(9, 5), columns=list('ABCDE')) 插入 T 列,并打上时间戳df.insert(value=pd.Timestamp('2017-10-1'),loc=0,column='Time') 将 1, 3, 5 列的 1,3,5 行置为缺失值df.iloc[[1,3,5,7], [0,2,4]] = np.nan 将 2, 4, 6 列的 2,4,6 行置为缺失值df.iloc[[2,4,6,8], [1,3,5]] = np.nan 我们用相同的标量值替换 NaN,比如用 0。 df.fillna(0) 注意,这里的填充并不会直接覆盖原数据集,你可以重新输出 df 比较结果。 除了直接填充值,我们还可以通过参数,将缺失值前面或者后面的值填充给相应的缺失值。例如使用缺失值前面的值进行填充: df.fillna(method='pad') 或者是后面的值: df.fillna(method='bfill') 最后一行由于没有对于的后序值,自然继续存在缺失值。 上面的例子中,我们的缺失值是间隔存在的。那么,如果存在连续的缺失值是怎样的情况呢?试一试。首先,我们将数据集的第 2,4 ,6 列的第 3,5 行也置为缺失值。 df.iloc[[3,5], [1,3,5]] = np.nan 然后来正向填充: df.fillna(method='pad') 可以看到,连续缺失值也是按照前序数值进行填充的,并且完全填充。这里,我们可以通过 limit= 参数设置连续填充的限制数量。 df.fillna(method='pad', limit=1) 除了上面的填充方式,还可以通过 Pandas 自带的求平均值方法等来填充特定列或行。举个例子: df.fillna(df.mean()['C':'E']) 3.2 清除缺失值 dropna() 上面演示了缺失值填充。但有些时候,缺失值比较少或者是填充无意义时,就可以直接清除了。 由于填充和清除在赋值之前,均不会影响原有的数据。所以,我们这里依旧延续使用上面的 df。 df.dropna() 我们可以看到,dropna() 方法带来的默认效果就是,凡是存在缺失值的行均被直接移除。此时,dropna() 里面有一个默认参数是 axis=0,代表依据行来移除。 如果我们像将凡是有缺失值的列直接移除,可以将 axis=1,试一试。 df.dropna(axis=1) 四、插值 interpolate() 插值是数值分析中一种方法。简而言之,就是借助于一个函数(线性或非线性),再根据已知数据去求解未知数据的值。插值在数据领域非常常见,它的好处在于,可以尽量去还原数据本身的样子。 Pandas 中的插值,通过 interpolate() 方法完成,默认为线性插值,即 method='linear'。除此之外,还有{‘linear’, ‘time’, ‘index’, ‘values’, ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘barycentric’, ‘krogh’, ‘polynomial’, ‘spline’, ‘piecewise_polynomial’, ‘from_derivatives’, ‘pchip’, ‘akima’}等插值方法可供选择。 举个例子: import pandas as pd 生成一个 DataFramedf = pd.DataFrame({'A': [1.1, 2.2, np.nan, 4.5, 5.7, 6.9], 'B': [.21, np.nan, np.nan, 3.1, 11.7, 13.2]}) 对于上面存在的缺失值,如果通过前后值,或者平均值来填充是不太能反映出趋势的。这时候,插值最好使。我们用默认的线性插值试一试。 df.interpolate() 如果你熟悉 Matplotlib,我们可以将数据绘制成图看一看趋势。图中,第 2,3 点的坐标是我们插值的结果。 上面提到了许多插值的方法,也就是 method=。下面给出几条选择的建议: 如果你的数据增长速率越来越快,可以选择 method='quadratic'二次插值。 接下来,我们就时间序列中常遇到的一些需求类型,列举一些示例,并使用 Pandas 提供的方法进行处理。 3.1 时间戳 Timestamp 既然是时间序列类型的数据,那么就少不了时间戳这一关键元素。Pandas 中,我们有两个创建时间戳的方法,分别是:to_datatime和 Timestamp。 to_datatime 后面集中详说。首先看一看 Timestamp,它针对于单一标量,举个例子: import pandas as pd pd.Timestamp('2017-10-01') 如果要包含小时:分钟:秒: pd.Timestamp('2017-10-01 13:30:59') 当然,还支持其他的格式输入,比如: pd.Timestamp('1/10/2017 13:30:59') 3.2 时间索引 DatetimeIndex 在实际工作中,我们很少遇到用单个时间戳的情况。而大多数时候,是使用由时间戳构成的时间索引。 首先,我们来看一下如何使用 Pandas 创建时间索引。这里用到的方法为 date_range(),date_range() 和 python 自带的 range() 很相似。它可以用来创建一系列等间距时间,并作为 Series 或者 DataFrame 的索引。 date_range() 方法带有的默认参数如下: pandas.date_range(start=None, end=None, periods=None, freq=’D’, tz=None, normalize=False, start= :设置起始时间 import pandas as pd rng1 = pd.date_range('1/10/2017', periods=24, freq='H') 可以这样: rng2 = pd.date_range('1/10/2017', periods=10, freq='D') 我们可以发现 freq= 参数的特点: freq='s': 秒 freq='BM': 每个月最后一天 rng3 = pd.date_range('1/10/2017', periods=20, freq='1H20min') 所以,只要适当地组合,你可以生成任意想要的时间序列索引。 3.3 时间转换 to_datatime to_datatime 是 Pandas 用于处理时间序列时的一个重要方法,它可以将实参转换为时间戳。to_datatime 包含的默认参数如下: pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, box=True, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix') 输入列表,默认返回时间索引 DatetimeIndex。 3.3.1 输入标量 import pandas as pd pd.to_datetime('1/10/2017 10:00', dayfirst=True) 3.3.2 输入列表 pd.to_datetime(['1/10/2017 10:00','2/10/2017 11:00','3/10/2017 12:00']) 3.3.2 输入 Series pd.to_datetime(pd.Series(['Oct 11, 2017', '2017-10-2', '3/10/2017']), dayfirst=True) 3.3.2 输入 DataFrame pd.to_datetime(pd.DataFrame({'year': [2017, 2018], 'month': [9, 10], 'day': [1, 2], 'hour': [11, 12]})) 3.3.2 errors= 接下来,看一看 errors= 遇到无法解析的数据时,所对应的不同返回值。这个参数对于我们解析大量数据时非常有用。 pd.to_datetime(['2017/10/1', 'abc'], errors='raise') pd.to_datetime(['2017/10/1', 'abc'], errors='ignore') pd.to_datetime(['2017/10/1', 'abc'], errors='coerce') 3.4 时间序列检索 上面,我们介绍了时间索引 DatetimeIndex 的生成方法。那么,它主要是用来做什么呢? 答案当然是 Pandas 对象的索引啦。将时间变成索引的优点非常多,包含但不限于: 查找和检索特定日期的字段非常快。 import pandas as pd ts = pd.DataFrame(np.random.randn(100000,1), columns=['Value'], index=pd.date_range('20170101', periods=100000, freq='T')) 当我们对数据进行快速检索是,其实和除了 Series 和 DataFrame 数据别无二致。例如: 检索 2017 年 3 月 2 号的数据: ts['2017-3-2'] 检索 2017 年 3 月 3 号下午 2 点到 5 点 23 分之间的数据: ts['2017-3-2 14:00:00':'2017-3-2 17:23:00'] 总之,一切在 Series 和 DataFrame 上可以用的数据选择与定位的方法,像 iloc(), loc() 等均可以用于时间序列,这里就不再赘述了。 3.5 时间序列计算 在 Pandas 中,包含有很多可以被加入到时间序列计算中去的类,这些被称为 Offsets 对象。 关于这一点,我们举出几个例子就一目了然了。例如: import pandas as pd dt = pd.Timestamp('2017-10-1 10:59:59') dt + offsets.DateOffset(months=1, days=2, hour=3) # 增加时间 又或者我们减去 3 个周的时间: dt - offsets.Week(3) 看明白了吧。这类的对象非常多,就不再一一演示,通过表格列举如下: 3.6 其他方法 最后,再介绍几个与时间序列处理相关的方法。 移动 Shifting shifting 可以将数据或者时间索引沿着时间轴的方向前移或后移,举例如下: import pandas as pd 生成一个时间系列数据集ts = pd.DataFrame(np.random.randn(7,2), columns=['Value1','Value2' ], index=pd.date_range('20170101', periods=7, freq='T')) 接下来开始移动。 ts.shift(3) ts.shift(-3) 那么,想移动索引怎么办?这里使用 tshift()。 ts.tshift(3) 向前移动索引就不再演示了,同样可以通过负号完成。除此之外,shift() 是可以接受一些参数的,比如 freq=''。而这里的 freq='' 参数和上文在介绍 时间索引 DatetimeIndex 时提到的一致。 举个例子: ts.shift(3, freq='D') # 日期向后移动 3 天 所以说,shifting 可以让我们更加灵活地去操作时间序列数据集,完成数据对齐等目标。 重采样 Resample 重采样,即是将时间序列从一个频率转换到另一个频率的过程。实施重采样的情形如下: 有时候,我们的时间序列数据集非常大,比如百万级别甚至更高。如果将全部数据用于后序计算,其实很多情况下是没有必要的。此时,我们可以对原有的时间序列进行降频采样。 import pandas as pd 生成一个时间系列数据集ts = pd.DataFrame(np.random.randn(50,1), columns=['Value' ], index=pd.date_range('2017-01', periods=50, freq='D')) 首先,可以升频采样,间隔变成小时。但是,由于间隔变小,我们就必须对新增加的行进行填充。 ts.resample('H').ffill() 下面,接着开始降频采样,从 1 天变成 5 天: ts.resample('5D').sum() |
def getComments(movieId, pageNum):
eachCommentList = [];
if pageNum>0:
start = (pageNum-1) * 20
else:
return False
requrl = 'https://movie.douban.com/subject/' +str( movieId) + '/comments' +'?' +'start=' + str(start) + '&limit=20'
print(requrl)
html_data = rq.get(requrl).content
soup = bs(html_data, 'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
for item in comment_div_lits:
if item.find_all('p')[0].string is not None:
eachCommentList.append(item.find_all('p')[0].string)
return eachCommentList
import pandas as pd
import matplotlib.pyplot as plt
from bs4 import BeautifulSoup as bs
import jieba
import numpy as np
import re
from wordcloud import WordCloud
url='https://movie.douban.com/subject/27008416/comments'
import requests as rq
commentList = []
for i in range(100):
num = i + 1
commentList_temp = getComments(27008416, num)
commentList.append(commentList_temp)
>>> commentList[:1]#第一页评论
[[' 男二人设其实挺苏的,热血纯情忠犬少年还是游泳冠军选手(越说越觉得像举重里的郑
俊亨。。。),奈何演员选得太接地气了这cp实在是不太好磕。\n ', ' 好久没有
看过这么温馨又不尴尬演技还在线的校园青春剧了,上一部还是《恶作剧之吻》。 剧组是
很有心的,每一集最后的彩蛋很棒。看到里面的递情书 去网吧 默写单词 老师的唠叨 陈
小希扮演白娘子,又想起了以前的校园时光。\n ', ' 33岁老阿姨,3集看哭2次,
傻笑20次……\n ', ' 放出来的片花很甜很吸引人,可是正片太拖沓了吧,剧情像
是各种小段子东拼西凑起来的,手机用小灵通然而qq聊天气泡都是最新版\n ', '
很尴尬,而且很讨厌这种男生酷女生傻的组合~要怪就怪最好的我们拍的太合我意了\n
', ' 零五年的故事背景,女主桌上是17年的知音漫客,用的是17年版本的qq还用了个
性气泡……我满脸都是excuse me拜托既然要弄回忆杀那就好好把年代相关的道具做好OK?
看了第一集完全被女主的傻白甜性格雷到,这样的女孩子为毛会被学神喜欢???怕了怕了
,我还是再去重刷一遍最好的我们吧\n ', ' 可能是预期太高,前几集看来,演技
生涩了点,节奏平淡了点,不过颜值和色调蛮舒服的……\n ', ' 预告即全剧最佳
。正片太尬了,剪辑也有问题,故事讲得很不连贯。曾以为这剧是清流,其实也就那样。不
会再浪费时间看了。\n ', ' 这身高差太棒了!图书馆那一幕少女心泛滥了!\n
', ' 男主一脸二傻子样。三分钟都没有看不下去了。\n ', ' 无脑素食盗版
《恶作剧之吻》,看完了前2集,只想重温台版恶吻\n ', ' 年度最失望 演技什么
的都不计较毕竟是新人 男女主颜值也都在线 但是作为忠实淑芬剧情改成这个样子真他妈的
想说脏话(哦 我已经说了)跟烂俗的三角恋还有什么区别 我们全宇宙最可爱的陈小希最温
暖的小江医生 永远只在书里了\n ', ' 我喜欢你,你会知道。怀念那段单纯的美好
时光。\n ', ' 垃圾!是我见过最长的mv!\n ', ' 年度最期待MV,配垃圾
长剧情。\n ', ' 抱歉,我去看隔壁你好旧时光了。半集弃。\n ', ' 剧情
太弱,营销太过。演技制作都不够水平啊。\n ', ' 预告即巅峰系列\n ',
' 原著党很气了…\n ', ' 预告全片能看精华系列。。。。\n ']]
#将列表中的数据转换为字符串
comments = ''
for k in range(len(commentList)):
comments = comments + (str(commentList[k])).strip()
#使用正则表达式去除标点符号
pattern = re.compile(r'[\u4e00-\u9fa5]+')
filterdata = re.findall(pattern, comments)
cleaned_comments = ''.join(filterdata)
#使用结巴分词进行中文分词
segment = jieba.lcut(cleaned_comments)
words_df=pd.DataFrame({'segment':segment})
segment
segment
0 男
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 了
... ...
4728 泠冽
4729 撕碎
4730 支票
4731 扔回去
4732 说
4733 阿姨
4734 支票
4735 兑现
4736 太
4737 麻烦
4738 钱
4739 还是
4740 打
4741 我
4742 支付宝
4743 吧
4744 怎么
4745 说
4746 呢
4747 总
4748 觉着
4749 这种
4750 剧
4751 有些
4752 脑残
4753 挺
4754 平淡
4755 看看
4756 还行
4757 吧
#去掉停用词,先下载https:/wendy1990/short_text_classification/blob/master/conf/stopwords.txt
stopwords=pd.read_csv("short_text_classification/conf/stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')#quoting=3全不引用words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
segment
0 男
1 二人
2 设
4 挺苏
6 热血
7 纯情
8 忠犬
9 少年
11 游泳
12 冠军
13 选手
14 越
15 说
16 越
17 觉得
19 举重
20 里
22 郑俊亨
23 奈何
24 演员
25 选得
26 太
27 接地
28 气
31 实在
33 不太好
34 磕
35 好久
37 看过
39 温馨
... ...
4716 那种
4717 贱人
4720 支票
4721 离开
4723 儿子
4725 女主角
4727 一脸
4728 泠冽
4729 撕碎
4730 支票
4731 扔回去
4732 说
4733 阿姨
4734 支票
4735 兑现
4736 太
4737 麻烦
4738 钱
4742 支付宝
4745 说
4746 呢
4747 总
4748 觉着
4749 这种
4750 剧
4752 脑残
4753 挺
4754 平淡
4755 看看
4756 还行
[2818 rows x 1 columns]
#统计词频
words_stat=words_df.groupby(by=['segment'])['segment'].agg({"计数":np.size})
words_stat=words_stat.reset_index().sort_values(by=["计数"],ascending=False)
segment 计数
354 喜欢 39
244 剧情 37
931 演技 32
1399 青春 31
437 女主 31
1008 男主 28
408 太 25
1069 真的 20
986 甜 20
1316 这种 18
1022 男女 17
1269 说 17
460 好看 17
1247 觉得 16
1155 美好 16
1162 老 14
240 剧 14
331 吻 14
1018 男二 13
1413 预告 13
615 恶作剧 12
523 差 12
811 有点 11
32 一集 11
928 演员 11
1296 身高 11
308 可爱 11
486 实在 11
1314 这剧 10
844 校园 10
... ... ..
554 开拍 1
552 开 1
551 延播 1
549 庆幸 1
548 幽默 1
547 幸小 1
544 年华 1
541 平面 1
539 平台 1
538 干脆 1
537 干胡 1
562 强大 1
563 强迫症 1
565 当好 1
579 微博上 1
587 心痛 1
585 心江辰 1
584 心思 1
583 心态 1
582 心女主 1
581 心动 1
577 很苏 1
566 当成 1
575 很棒 1
574 很快 1
573 很差 1
571 影子 1
568 彩小 1
567 当魂 1
724 撕 1
[1448 rows x 2 columns]
#用词云进行显示
wordcloud=WordCloud(font_path="c:\windos\fonts\simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
word_frequence_list = []
for key in word_frequence:
temp = (key,word_frequence[key])
word_frequence_list.append(temp)
wordcloud=wordcloud.fit_words(word_frequence_list)
plt.imshow(wordcloud)
plt.show() |
pyechart https:/napjon/krisk https:/spatie/laravel-responsecache * * * * * sh /web/project/src/shell/repair_build_order.sh
#!/bin/bash
cd /web/project/src
for (( i = 1; i < 60; i = i + 1 ))
do
$(/usr/bin/php index.php task_run > /dev/null 2>&1 &)
sleep 1
done
exit 0 redis-cli连接redis后,可以使用==monitor==查看队列情况。 ini_set('default_socket_timeout', -1);
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$channelname = c('mail_channel');
try
{
$redis->subscribe(array($channelname), 'mailsend');
}catch(Exception $e)
{
echo $e->getMessage();
}
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$info = array();
$info['to'] = $to;
$info['subject'] = $subject;
$info['content'] = $content;
if($ret = $redis->publish( c('mail_channel') , serialize($info) ))
{
return send_result( 'send to ' . $to . ' add to queue' );
}
else
return send_error( $ret ); PHP实现非对称加密 https://segmentfault.com/a/1190000003975283 https:/wuzhc/demo/blob/master/shejimoshi/Factory.php 设计模式 $fp = fopen($filename, 'a+');
if (!$fp) {
echo 'can\'n open filename';
exit;
}
$retries = 0;
do {
if ($retries > 0) {
sleep(1);
}
$retries += 1;
} while (!flock($fp, LOCK_EX) && $retries < 3);
fwrite($fp, 'you content');
flock($fp, LOCK_UN);
fclose($fp);
$data = file_get_contents('./test.png');
$http_entity_body = $data;
//$http_entity_type = 'application/x-www-form-urlencoded';
$http_entity_type = 'multipart/form-data'; //经过测试,entityType设置为multipart/form-data时候也可以用php://input
$http_entity_length = strlen($http_entity_body);
$host = 'wuzhc.cm';
$port = 80;
$path = '/test/input/receive.php';
$fp = fsockopen($host, $port, $error_no, $error_desc, 30);
if ($fp) {
fputs($fp, "POST {$path} HTTP/1.1\r\n");
fputs($fp, "Host: {$host}\r\n");
fputs($fp, "Content-Type: {$http_entity_type}\r\n");
fputs($fp, "Content-Length: {$http_entity_length}\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $http_entity_body . "\r\n\r\n");
while (!feof($fp)) {
$d .= fgets($fp, 4096);
}
fclose($fp);
echo $d;
}
class ParentClass {
public static function name()
{
return __CLASS__;
}
public static function create()
{
return new static();
}
public static function test()
{
return self::name(); //改为static::name() 就可以了
}
}
class ChildClass extends ParentClass {
public static function name()
{
return __CLASS__;
}
}
echo ChildClass::test();
$pipe = $redis->multi(Redis::PIPELINE);
for ($i = 0; $i < 10; $i++) {
$pipe->set("ss$i", str_pad($i, 4, '0', 0));
$pipe->get("ss$i");
}
$replies = $pipe->exec();
$requestUrls = [];
for ($i=0; $i<10; $i++) {
array_push($requestUrls, 'http://104.194.84.229/zcshop/frontend/web/test/sms');
}
$mh = curl_multi_init();
$chs = [];
foreach ($requestUrls as $url) {
$chs[] = $ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3000);
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8888');
curl_multi_add_handle($mh, $ch);
}
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
$res = [];
foreach ($chs as $k => $ch) {
$res[] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
echo $k . ' success' . PHP_EOL;
}
curl_multi_close($mh); |
200行代码学会微信H5支付,附php可用代码 https://www.wangwenxiao.com/208 import socket
import struct
ip = '119.75.218.77'
num_ip=socket.ntohl(struct.unpack("I",socket.inet_aton(str(ip)))[0])
num_ip
2001459789L
ip = socket.inet_ntoa(struct.pack('I',socket.htonl(num_ip)))
ip
'119.75.218.77'
function rangeDaysAfterTimeStamp($startTimestamp, $daysNum = 1)
{
$range = [];
do {
$range[] = date('Y-m-d 00:00:00', $startTimestamp + (-- $daysNum) * 86400);
} while ($daysNum);
rsort($range);
return $range;
}
>>> rangeDaysAfterTimeStamp(strtotime('2017-11-11'),7)
=> [
"2017-11-17 00:00:00",
"2017-11-16 00:00:00",
"2017-11-15 00:00:00",
"2017-11-14 00:00:00",
"2017-11-13 00:00:00",
"2017-11-12 00:00:00",
"2017-11-11 00:00:00"
]
$ch = curl_init();
$fp=fopen('./girl.jpg', 'w');
curl_setopt($ch, CURLOPT_URL, "http://远程服务器地址马赛克/girl.jpg");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($ch, CURLOPT_FILE, $fp);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
fclose($fp);
$size = filesize("./girl.jpg");
if ($size != $info['size_download']) {
echo "下载的数据不完整,请重新下载";
} else {
echo "下载数据完整";
}https://segmentfault.com/a/1190000006220620 https://linkedinfo.co/infosbytags?tags=php
function array_sort($array, $on, $order=SORT_ASC)
{
$new_array = array();
$sortable_array = array();
if (count($array) > 0) {
foreach ($array as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
if ($k2 == $on) {
$sortable_array[$k] = $v2;
}
}
} else {
$sortable_array[$k] = $v;
}
}
switch ($order) {
case SORT_ASC:
asort($sortable_array);
break;
case SORT_DESC:
arsort($sortable_array);
break;
}
foreach ($sortable_array as $k => $v) {
$new_array[$k] = $array[$k];
}
}
return $new_array;
}function array_orderby()
{
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
// ini_set(‘default_socket_timeout’, -1); https:/TIGERB/easy-tips/blob/master/redis/subscribe-publish/subscribe.php
$redis = new \Redis();
$redis->pconnect('127.0.0.1', 6379);
//订阅
echo "订阅msg这个频道,等待消息推送... \n";
$redis->subscribe(['msg'], 'callfun');
function callfun($redis, $channel, $msg)
{
print_r([
'redis' => $redis,
'channel' => $channel,
'msg' => $msg
]);
}
$redis->publish('msg', '来自msg频道的推送');
echo "msg频道消息推送成功~ \n";
$redis->close(); 如果每天记录当天的积分排行榜,那么其他花样百出的榜单也就简单了。 比如“昨日积分榜”: bashZREVRANGE rank:20150331 0 9 withscores bashZUNIONSTORE rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 rank:20150326 rank:20150327 rank:20150328 rank:20150329 WEIGHTS 1 1 1 1 1 1 1 bashZREVRANGE rank:last_week 0 9 withscores http://blog.csdn.net/zheng0518/article/details/47280745 我的理解就是, 任务来了, 2 写入redis 首先我在 redis 中维护一个 sorted set。score 的值为:YYYYMMDD+HOUR,如 2015061020。当 A 用户邀请了 B 用户之后,我就推算一下 24 小时后,是多少,把 B 用户的值写入 set 中。然后另外起个定时任务,每小时读一次这个 set,读出比当前时间小的 score,批量处理一次。
3.JAVA 或者其他分布式架构的 $format = "<xml>
<Encrypt><![CDATA[%s]]></Encrypt>
<MsgSignature><![CDATA[%s]]></MsgSignature>
<TimeStamp>%s</TimeStamp>
<Nonce><![CDATA[%s]]></Nonce>
</xml>";
$format = <<<XML
<xml>
<Encrypt><![CDATA[%s]]></Encrypt>
<MsgSignature><![CDATA[%s]]></MsgSignature>
<TimeStamp>%s</TimeStamp>
<Nonce><![CDATA[%s]]></Nonce>
</xml>
XML;
$xml = new \DOMDocument();
$xml->loadXML($xmltext);
$array_e = $xml->getElementsByTagName('Encrypt');
$encrypt = $array_e->item(0)->nodeValue;
$xml = (array) simplexml_load_string(file_get_contents('php://input'), 'SimpleXMLElement', LIBXML_NOCDATA);
http://blog.csdn.net/wuxing26jiayou/article/category/6689523 PHP 冒泡排序
public static function getCurrentMonthDates() {
$dt = Carbon::now();
$days = $dt->daysInMonth;//天数
$dates = array();
for ($day = 1; $day <= $days; $day++) {
$dt->day = $day;
$dates[] = $dt->format('Ymd');
}
return $dates;
}
查找表中name字段和email字段相同的数据:
https://segmentfault.com/a/1190000002508404
select * from demo_table as a, demo_table as b where a.id=b.id and a.name=b.email;
create table tmp_table as select min(id) from demo_table group by email;
delete from demo_table where id not in (select * from tmp_table);
drop table tmp_table;
$season = ceil(date('n') /3); //获取月份的季度
上季度开始时间 mktime(0, 0, 0, ($season - 2) * 3 + 1, 1, date('Y'));
上季度结束时间 mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')) - 1;
本周之前几周的结束时间 date('d') - date('w') + 7 - 7 * $beforeWeeks
本周之前几周的开始时间 date('d') - date('w') + 1 - 7 * $beforeWeeks
date('t',strtotime('2017-02-02')) //2月 28 天
function rangeDaysAfterTimeStamp($startTimestamp, $daysNum = 1)
{
$range = [];
do {
$range[] = date('Y-m-d 00:00:00', $startTimestamp + (-- $daysNum) * 86400);
} while ($daysNum);
rsort($range);
return $range;
}
function rangeDays($beginTimestamp, $endTimestamp)
{
$beginTimestamp = strtotime(date('Y-m-d', $beginTimestamp));
$endTimestamp = strtotime(date('Y-m-d', $endTimestamp));
$range = [];
$i = 0;
do {
$time = $beginTimestamp + $i * 86400;
$range[] = date('Y-m-d 00:00:00', $time);
$i++;
} while ($time < $endTimestamp);
return $range;
} |
$catList = [
'1' => ['id' => 1, 'name' => '颜色', 'parent_id' => 0],
'2' => ['id' => 2, 'name' => '规格', 'parent_id' => 0],
'3' => ['id' => 3, 'name' => '白色', 'parent_id' => 1],
'4' => ['id' => 4, 'name' => '黑色', 'parent_id' => 1],
'5' => ['id' => 5, 'name' => '大', 'parent_id' => 2],
'6' => ['id' => 6, 'name' => '小', 'parent_id' => 2],
'7' => ['id' => 7, 'name' => '黄色', 'parent_id' => 1],
];$treeData = [];// 保存结果
foreach ($catList as $item) {
if (isset($catList[$item['parent_id']]) && ! empty($catList[$item['parent_id']])) {// 肯定是子分类
$catList[$item['parent_id']]['children'][] = &$catList[$item['id']];
} else {// 肯定是一级分类
$treeData[] = &$catList[$item['id']];
}
}
$result = [
['id' => 1, 'name' => '颜色', 'children' => [
['id' => 3, 'name' => '白色'],
['id' => 4, 'name' => '黑色'],
['id' => 7, 'name' => '黄色']
]],
['id' => 2, 'name' => '规格', 'children' => [
['id' => 5, 'name' => '大'],
['id' => 6, 'name' => '小']
]]
];
$ php artisan tinker
PHP Fatal error: Cannot use PhpParser\Node\Scalar\String as String because 'Str
ing' is a special class name in D:\soft\wamp\www\laravel_web\vendor\psy\psysh\sr
c\Psy\CodeCleaner\MagicConstantsPass.php on line 19
[Symfony\Component\Debug\Exception\FatalErrorException]
Cannot use PhpParser\Node\Scalar\String as String because 'String' is a spe
cial class name
http://cn.php.net/manual/zh/reserved.other-reserved-words.php 以下关键字不可被用于类名、接口名和trait名,并且它们被禁止用于命名空间。 https:/nikic/PHP-Parser/issues/248
$ psysh
PHP Fatal error: Uncaught Error: Class 'Psy\Shell' not found in C:\Users\vhalll
sp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psysh:108
Stack trace:
#0 {main}
thrown in C:\Users\vhalllsp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psys
h on line 108
Fatal error: Uncaught Error: Class 'Psy\Shell' not found in C:\Users\vhalllsp\Ap
pData\Roaming\Composer\vendor\psy\psysh\bin\psysh:108
Stack trace:
#0 {main}
thrown in C:\Users\vhalllsp\AppData\Roaming\Composer\vendor\psy\psysh\bin\psys
h on line 108
http://psysh.org/ composer g require psy/psysh:@stable
>>> r=req.get(wx,headers={'cookie':c},verify=False)
d:\python27\lib\site-packages\requests\packages\urllib3\util\ssl_.py:132: Insecu
rePlatformWarning: A true SSLContext object is not available. This prevents urll
ib3 from configuring SSL appropriately and may cause certain SSL connections to
fail. You can upgrade to a newer version of Python to solve this. For more infor
mation, see https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-war
nings
InsecurePlatformWarning
d:\python27\lib\site-packages\requests\packages\urllib3\connectionpool.py:852: I
nsecureRequestWarning: Unverified HTTPS request is being made. Adding certificat
e verification is strongly advised. See: https://urllib3.readthedocs.io/en/lates
t/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
curl 返回 false $curl_errno = curl_errno($curl);
$curl_error = curl_error($curl);
SSL certificate problem: unable to get local issuer certificate 下载https://curl.haxx.se/ca/cacert.pem
php.ini curl.cainfo = D:\phpStudy\php\cacert.pem
Fri Dec 15 15:57:13 2017 (21320): Fatal Error Unable to open base address file
http://windows.php.net/download/
$ /d/soft/wamp/php/php artisan tinker
Warning: date(): It is not safe to rely on the system's timezone settings. You a
re *required* to use the date.timezone setting or the date_default_timezone_set(
) function. In case you used any of those methods and you are still getting this
warning, you most likely misspelled the timezone identifier. We selected the ti
mezone 'UTC' for now, but please set date.timezone to select your timezone. in D
:\soft\wamp\www\laravel_web\config\services.php on line 122
Fatal error: Call to undefined function Illuminate\Foundation\Bootstrap\mb_inter
nal_encoding() in D:\soft\wamp\www\laravel_web\vendor\laravel\framework\src\Illu
minate\Foundation\Bootstrap\LoadConfiguration.php on line 43
vi php.ini
date.timezone = "Asia/Shanghai"
extension=php_mbstring.dll
1.在使用requests前加入:requests.packages.urllib3.disable_warnings()
2.为requests添加verify=False参数,比如:r = requests.get('https://blog.bbzhh.com',verify=False) |
简单实现redis队列,模拟下单 https:/linganmin/simple-php-queue-redis.git |
The text was updated successfully, but these errors were encountered: