python的json库
使用过json5,数据量大时速度不能忍。
orjson 速度比较快。
安装(conda-forge):
conda install orjson
requests库
使用curl调试调用参数
建议copy了 curl后, 从 https://curl.trillworks.com/ 获取代码修改
SSLError: HTTPSConnectionPool
参考: https://www.cnblogs.com/hum0ro/p/9536033.html
方案1:添加参数 verify=False
response = requests.get('http://www.baidu.com/', headers = header, verify=False)
会有提示 InsecureRequestWarning: Unverified HTTPS request is being made to host
, 消除该警告:
import urllib3
urllib3.disable_warnings()
# 在请求代码 requests.get(url...) 前添加如下代码即可
requests.packages.urllib3.disable_warnings()
r = requests.get(url...)
方案2:安装如下的模块,不一定有用
conda install cryptography pyOpenSSL certifi
10060错误: ProtocolError: ('Connection aborted.', TimeoutError(10060...
可以尝试的解决方案:
- 延长访问频率:
time.sleep(15)
- 随机切换User-Agent:
user_agent_list = ["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15",
]
headers['User-Agent'] = random.choice(user_agent_list)
UnicodeEncodeError
报错信息:
UnicodeEncodeError: 'latin-1' codec can't encode character '\u2026' in position 30: ordinal not in range(256)
有可能是 User-Agent 等参数里有特殊字符, 比如下面的 (…):
"Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0",
ConnectionError
报错信息类似:
ConnectionError: HTTPSConnectionPool(host='www.xxx.org', port=443): Max retries exceeded with url
http的连接数超过最大限制,默认的情况下连接是Keep-alive的,所以这就导致了服务器保持了太多连接而不能再新建连接. 解决方式:
- header中不使用持久连接:
'Connection': 'close',
- 请求前设置:
requests.adapters.DEFAULT_RETRIES = 5
类似连接这类问题,使用JMS这类代理一般都可以解决,只是连接速度有可能降低.
##使用Numba加速python科学计算代码
win10下安装Numba
安装参考Numba官网
windows10平台下的安装(NVIDIA显卡),其中cuda是NVIDIA显卡工具:
conda install numba
conda install cudatoolkit
检查安装:
C:\>python
Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import numba
>>> numba.__version__
'0.51.2'
C:\>numba
numba: error: the following arguments are required: filename
(base) C:\>numba --sysinfo
System info:
--------------------------------------------------------------------------------
__CUDA Information__
CUDA Device Initialized : True
CUDA Driver Version : 11000
CUDA Detect Output:
Found 1 CUDA devices
id 0 b'GeForce GTX 1650' [SUPPORTED]
compute capability: 7.5
pci device id: 0
pci bus id: 1
Summary:
1/1 devices are supported
速度测试
# -*- coding: utf-8 -*-
from numba import njit,float64
import datetime
# 不使用numba的情况
def f_1(n):
x = 123.45
y = 678.9
for i in range(1,n):
temp = x * y / i
return temp
# 使用 numba
@njit
def f_2(n):
x = 123.45
y = 678.9
for i in range(1,n):
temp = x * y / i
return temp
# 使用 numba
@njit (float64(float64))
def f_3(n):
x = 123.45
y = 678.9
for i in range(1,n):
temp = x * y / i
return temp
start=datetime.datetime.now()
r1 = f_1(100000000)
elapsed_1 = (datetime.datetime.now() - start) # 秒数
elapsed_1 = elapsed_1.microseconds
start=datetime.datetime.now()
r2=f_2(100000000)
elapsed_2 = (datetime.datetime.now() - start) # 秒数
elapsed_2 = elapsed_2.microseconds
start=datetime.datetime.now()
r3=f_3(100000000)
elapsed_3 = (datetime.datetime.now() - start) # 秒数
elapsed_3 = elapsed_3.microseconds
print("函数1消耗微秒数:",elapsed_1)
print("函数2消耗微秒数:",elapsed_2)
print("函数1消耗微秒数:",elapsed_3)
print("函数1消耗微秒数/函数2消耗微秒数:",elapsed_1/elapsed_2)
print('r1,r2,r3:',r1,r2,r3)
'''输出:
函数1消耗微秒数: 250370
函数2消耗微秒数: 34907
函数1消耗微秒数: 0
函数1消耗微秒数/函数2消耗微秒数: 7.17248689374624
r1,r2,r3: 0.0008381020583810206 0.0008381020583810206 0.0008381020583810206
'''
数值计算中, Numba提升明显,指定参数类型时提速更夸张。一定用njit注解强制转换,并指定数据类型
python中含有None等情形或其他逻辑处理的写法:
def func_without_numba():
# 调用含有 Numba 代码的函数
try:
func_with_numba()
except:
# 这里写异常处理代码
pass
@njit(参数)
def func_with_numba()
# 不需要处理异常的数值计算代码
pass
使用pexpect和paramiko
paramiko示例
使用密匙登录到服务器,执行命令并回显
import paramiko # conda install paramiko
private_key = paramiko.RSAKey.from_private_key_file('path_to_keyfile')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname = server_ip, port=server_port,\
username=server_username, pkey=private_key)
stdin, stdout, stderr = ssh.exec_command('ifconfig')
result = stdout.read()
print(result.decode())
ssh.close()
pexpect示例
使用密匙通过 ssh同步本地和远程文件夹。
windows系统下,脚本中不能使用 pexpect 包,所以该脚本不支持windows。
import pexpect # conda install pexpect
# private_key = $HOME/.ssh/somekey
# 必须在 $HOME/.ssh/ 目录下
# chmod 700 /home/userName/.ssh/somekey
# private_key = '/home/userName/.ssh/somekey'
cmd:rsync --delete -avzP /本地文件夹路径/ -e 'ssh -p port_num_str -i private_key ' root@远程服务器IP::rsync模块名
ssh = pexpect.spawn(cmd,timeout = timeout,encoding='utf-8')
ssh.logfile_read = sys.stdout # 返回执行过程中的内容
i = ssh.expect('Password:')
if i==0:
ssh.sendline(rsync密码)
ssh.read()
ssh.close()
DBUtils:一套Python数据库连接池包
DBUtils是一套Python数据库连接池包,允许对非线程安全的数据库接口进行线程安全包装。DBUtils 仅提供给了连接池管理,实际的数据库操作依然是由符合 DB-API 2 标准的目标数据库模块完成的。
DBUtils提供两种外部接口:
- PersistentDB :提供线程专用的数据库连接,并自动管理连接-。
- PooledDB :提供线程间可共享的数据库连接,并自动管理连接。
实测证明 PersistentDB 的速度是最高的,但是在某些特殊情况下,数据库的连接过程可能异常缓慢,而此时的PooledDB则可以提供相对来说平均连接时间比较短的管理方式。可以考虑直接用PooledDB.
连接池对象只初始化一次,一般可以作为模块级代码来确保。
示例参考: https://cito.github.io/DBUtils/UsersGuide.html
PostgreSQL连接池示例,需要先安装相关的模块:
conda install psycopg2
pip install DBUtils
示例代码:
import psycopg2
from dbutils.pooled_db import PooledDB
pgpool = PooledDB(creator=psycopg2,mincached=0,maxcached=10,\
host='127.0.0.1',
port=5432,
user='postgres',
password='pgpassword',
database='pgdb')
sql = 'select * from tbname;'
db = pgpool.connection()
cur = db.cursor()
cur.execute(sql)
result = cur.fetchall()
cur.close()
db.close()
BeautifulSoup库
安装:conda install beautifulsoup4
获取指定class样式的div
soup=BeautifulSoup(html)
result = soup.find_all(name='div',attrs={"class":"footer"})#按照字典的形式给attrs参数赋值
GuessedAtParserWarning
添加类似 lxml的解析器:
soup = BeautifulSoup(r.text,"lxml")
示例: 抓取弯曲日报第一期内容并解析
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
def get_wanqu_article(issue):
# 获取湾区日报 wanqu.co 的第 issue 期html 页面内容
print("抓取第" + str(issue) + "期文章")
url = "https://wanqu.co/issues/" + str(issue)
r = requests.get(url)
r.encoding="UTF-8"
if r.status_code==200:
html = r.text
else:
print("抓取湾区日报第" + str(issue) + "期失败")
html = ''
'''
解析获取的 html,输出文章条目:
- 弯曲日报期数:2014/08/06 第1期
- 文章题目:StackOverflow: 25台服务器,每月560,000,000 page views
- 文章源链: 原链 highscalability.com
- 点评:湾区日报作者点评
'''
if len(html) > 0:
soup = BeautifulSoup(html,"lxml")
# 获取title
tags = soup.find_all('h1', class_="wq-header")
title = tags[0].text
# 获取所有文章在wanqu.co的链接
'''
<a href="https://wanqu.co/a/9/stackoverflow-25台服务器每月560000000-page-views/"
style="color: #000;" title="StackOverflow: 25台服务器,每月560,000,000 page views">
<h2 class="wq-header" style="margin-bottom:4px;">StackOverflow: 25台服务器,每月560,000,000
page views</h2>
</a>
'''
tags = soup.find_all('a')
article_url_list = []
for tag in tags:
tags2 = tag.find_all('h2', class_="wq-header")
if len(tags2)>0:
article_url_list.append(tag.get('href'))
# 抓取并解析每一篇文章
article_list = []
for url in article_url_list:
r = requests.get(url)
r.encoding="UTF-8"
if r.status_code==200:
article_html = r.text
else:
print("抓取文章html失败:" + url)
article_html = ''
if len(article_html)>0:
# [title,url,lead]
article_info = parse_article_html(article_html)
article_list.append(article_info)
return [title,article_list]
else:
return []
def parse_article_html(article_html):
soup = BeautifulSoup(article_html,"lxml")
# 获取title
tags = soup.find_all('h1', class_="wq-header")
title = tags[0].text
# 获取原链
tags = soup.find_all('a')
for i in range(len(tags)):
if "原链" in tags[i].text:
url = tags[i].get('href')
url = url[:url.find("?utm_source")]
break
# 获取点评
tags = soup.find_all('div', class_="lead")
lead = tags[0].text.strip()
return [title,url,lead]
if __name__=="__main__":
info = get_wanqu_article(1)
示例: 抓取必应(bing)每日壁纸脚本
本脚本从 https://bing.ioliu.cn/ 获取图片,并保存到指定目录
# -*- coding: utf-8 -*-
# 获取 bing(必应)的每日壁纸
# bing官方 api只能获取7天的,参考:https://blog.csdn.net/m0_37682004/article/details/82314055
# 本脚本从 https://bing.ioliu.cn/ 获取图片
import requests
# conda install beautifulsoup4 lxml
from bs4 import BeautifulSoup
import os
from PIL import Image # conda install Pillow
def get_all_file_names(local_dir):
# 获取指定目录下的所有文件名,返回文件名列表
pic_file_list=[]
for root, dirs, files in os.walk(local_dir):
for name in files:
pic_file_list.append(name)
return pic_file_list
def get_html_content(pageNum):
# 页码url: https://bing.ioliu.cn/?p=1, 首页为1
url = "https://bing.ioliu.cn/?p=" + str(pageNum)
print("获取第 " + str(pageNum) + "页html内容")
html = requests.get(url)
return html.content
def get_pic_url_list(htmlContent):
# 获取html中的图片 url列表
'''
<img class="progressive__img progressive--is-loaded"
src="http://h1.ioliu.cn/bing/BubbleNebula_ZH-CN2787112807_1920x1080.jpg"
data-progressive="http://h1.ioliu.cn/bing/BubbleNebula_ZH-CN2787112807_1920x1080.jpg">
'''
soup = BeautifulSoup(htmlContent, 'lxml')
pics = soup.findAll('img')
url_list = []
for pic in pics:
if 'src' in pic.attrs:
url_list.append(pic.attrs['src'])
return url_list
def save_bing_pics(pageNumStart,pageNumEnd,local_dir):
pic_file_list = get_all_file_names(local_dir)
for pageNum in range(pageNumStart,pageNumEnd +1):
htmlContent = get_html_content(pageNum)
url_list = get_pic_url_list(htmlContent)
for pic_url in url_list:
pic_name = pic_url.split('/')[-1]
if pic_name not in pic_file_list:
pic_file_list.append(pic_name)
print("获取图片:" + pic_name)
html = requests.get(pic_url)
with open(os.path.join(local_dir,pic_name),'wb') as file:
print("保存图片:" + pic_name)
file.write(html.content)
else:
print("图片已存在:" + pic_name)
def clear_pic_files(width,height,local_dir):
# 清理图片文件,删除分辨率小于 width * height 的图片
fileNameListToDel = []
all_file_names = get_all_file_names(local_dir)
for file_name in all_file_names:
with Image.open(os.path.join(local_dir,file_name)) as imgFile:
# 宽,高
#print("图片 " + file_name + ":" + str(imgFile.width) + "*" + str(imgFile.height) )
if (imgFile.width < width) or (imgFile.height < height):
fileNameListToDel.append(file_name)
# 删除文件
for file_name in fileNameListToDel:
os.remove(os.path.join(local_dir,file_name))
if __name__=="__main__":
local_dir="D:/壁纸/bing"
save_bing_pics(1,4,local_dir)
clear_pic_files(1920,1080,local_dir)