Python3中遇到UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 25-45: ordinal not in range(128)

如果是python 2.x的话需要在文件中加上

# coding: utf-8 
reload(sys)
sys.setdefaultencoding("utf8")

但是Python3应当默认就使用utf8编码即使设置了这些也仍然不能正常打印。

最终查看了一下系统环境编码,发现问题(我的是ARM架构下的Ubuntu

>>> import sys
>>> sys.stdout.encoding  
'ANSI_X3.4-1968'

解决办法

1、设置环境变量LANG

在linux或Mac上设置环境变量的方式一样,在/etc/profile增加一行
export LANG=”en_US.UTF-8″
然后source /etc/profile

我当前系统默认已经是utf-8,采用第二种解决

2、使用PYTHONIOENCODING

在运行python命令前添加参数 PYTHONIOENCODING=utf-8 python3 api.py

该参数的解释可查看

https://docs.python.org/3.6/using/cmdline.html

python36实现批量查询指定长度的字母数字域名是否被注册

1、配合万网的域名查询接口

2、python36实现批量查询指定长度的字母数字域名是否被注册

3、使用笛卡尔积实现排列组合拼接域名

4、因为接口请求有限制,就不用多线程来速战速决了

# coding: utf-8

import time
import string
import logging
import requests
import itertools
from xml.etree import ElementTree as ET

"""
- returncode=200 表示接口返回成功 
- key=*.com表示当前check的域名 
- original=210 : Domain name is available 表示域名可以注册 
- original=211 : Domain name is not available 表示域名已经注册 
- original=212 : Domain name is invalid 表示域名参数传输错误 
- original=213 : Time out 查询超时
"""

logging.basicConfig(level=logging.INFO,
    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s - %(message)s',
    datefmt='%a, %d %b %Y %H:%M:%S',
    filename='domain.log')

domain_check_api = "http://panda.www.net.cn/cgi-bin/check.cgi?area_domain={}"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'}


def write_file(domain):
    with open("domain.txt", "a+") as f:
        f.write(f"{domain}\n")


def req_data(domain):
    try:
        result = requests.get(domain_check_api.format(domain), headers=headers)
        root = ET.XML(result.text)
        for node in root.iter('property'):
            code = node.find('returncode').text
            original = node.find('original').text
            if int(code) == 200 and '210' in original:
                write_file(domain)
                logging.info(f"[{domain}]可注册")
            else:
                logging.info(f"[{code}][{original}][{domain}]不可注册")
        time.sleep(0.1)
    except:
        pass


def main(sd, domain_length, domain_suffix):
    for ds in domain_suffix:
        for x in itertools.product(sd, repeat = domain_length):
            domain = f"{''.join(x)}.{ds}"
            req_data(domain)


if __name__ == "__main__":
    sd = string.digits    # 纯数字
    # sd = string.ascii_lowercase # 纯字母
    # sd = string.digits+string.ascii_lowercase # 数字字母组合
    domain_length = 4
    domain_suffix = ['cn', 'com.cn', 'com']
    main(sd, domain_length, domain_suffix)

使用python检查SSL证书到期情况

结合邮件告警和页面展示,再多的域名证书到期情况即可立马知道

# coding: utf-8 
# 查询域名证书到期情况

import re
import time
import subprocess
from datetime import datetime
from io import StringIO

def main(domain):
    f = StringIO()
    comm = f"curl -Ivs https://{domain} --connect-timeout 10"

    result = subprocess.getstatusoutput(comm)
    f.write(result[1])

    m = re.search('start date: (.*?)\n.*?expire date: (.*?)\n.*?common name: (.*?)\n.*?issuer: CN=(.*?)\n', f.getvalue(), re.S)
    start_date = m.group(1)
    expire_date = m.group(2)
    common_name = m.group(3)
    issuer = m.group(4)

    # time 字符串转时间数组
    start_date = time.strptime(start_date, "%b %d %H:%M:%S %Y GMT")
    start_date_st = time.strftime("%Y-%m-%d %H:%M:%S", start_date)
    # datetime 字符串转时间数组
    expire_date = datetime.strptime(expire_date, "%b %d %H:%M:%S %Y GMT")
    expire_date_st = datetime.strftime(expire_date,"%Y-%m-%d %H:%M:%S")

    # 剩余天数
    remaining = (expire_date-datetime.now()).days

    print ('域名:', domain)
    print ('通用名:', common_name)
    print ('开始时间:', start_date_st)
    print ('到期时间:', expire_date_st)
    print (f'剩余时间: {remaining}天')
    print ('颁发机构:', issuer)
    print ('*'*30)

    time.sleep(0.5)

if __name__ == "__main__":
    domains = ['www.01314.cn', 'www.51bbo.com'] 
    for domain in domains:
        main(domain)

结果

域名: www.01314.cn
通用名: www.01314.cn
开始时间: 2018-10-18 00:00:00
到期时间: 2019-10-18 12:00:00
剩余时间: 307天
颁发机构: Encryption Everywhere DV TLS CA - G1,OU=www.digicert.com,O=DigiCert Inc,C=US
******************************
域名: www.51bbo.com
通用名: 51bbo.com
开始时间: 2018-09-27 00:00:00
到期时间: 2019-09-27 12:00:00
剩余时间: 286天
颁发机构: Encryption Everywhere DV TLS CA - G1,OU=www.digicert.com,O=DigiCert Inc,C=US
******************************

采集soundcloud专辑

1、需要设置代理

2、滚屏加载更多歌曲

3、解析歌曲完整下载路径

import os
import time
import json
import requests
from selenium import webdriver
from scrapy.selector import Selector
from selenium.webdriver.support.ui import WebDriverWait

proxies = {
    "http": "http://192.168.1.88:1088",
    "https": "http://192.168.1.88:1088",
}

def music_download(url):
    file_name = url.split('?')[0].split('/')[-1]
    r = requests.get(url, stream=True)
    with open(f"music/{file_name}", 'wb') as f:
        f.write(r.content)
    if os.path.exists(file_name) and os.path.getsize(file_name) > 1*1000*1000:
        print(f"{file_name} download success, file size: {os.path.getsize(file_name)/1000/1000}M")
    else:
        print (f"{file_name} download fail.")

def music_index(url):
    url_desc_api = f"https://api.soundcloud.com/resolve?url={url}&client_id=LvWovRaJZlWCHql0bISuum8Bd2KX79mb"
    r = requests.get(url_desc_api, proxies=proxies)
    json_r = json.loads(r.text)
    sound_id = json_r['id']
    if not sound_id is None:
        url_download_api = f"https://api.soundcloud.com/i1/tracks/{sound_id}/streams?client_id=LvWovRaJZlWCHql0bISuum8Bd2KX79mb"
        sound_r = requests.get(url_download_api, proxies=proxies)
        json_sound_r = json.loads(sound_r.text)
        print (f"当前任务ID: {sound_id}")
        try:
            music_download_url = json_sound_r['http_mp3_128_url']
            if music_download_url:
                music_download(music_download_url)
        except:
            pass

def soundcloud_index():
    url = "https://soundcloud.com/beyond-synth"
    chromeOptions = webdriver.ChromeOptions()
    # 加入代理功能
    chromeOptions.add_argument(f"--proxy-server=http://192.168.1.88:1088")
    browser = webdriver.Chrome(chrome_options = chromeOptions)     
    browser.get(url)

    # 等待滚屏到最后
    js1 = 'return document.body.scrollHeight'
    js2 = 'window.scrollTo(0, document.body.scrollHeight)'
    old_scroll_height = 0
    while browser.execute_script(js1) >= old_scroll_height:
        old_scroll_height = browser.execute_script(js1)
        browser.execute_script(js2) 
        time.sleep(1)
    # 开始处理页面
    content = browser.find_elements_by_class_name('sound__coverArt')
    count = 1
    for c in content:
        single_url = c.get_attribute('href')
        music_index(single_url)
        time.sleep(1)
        print (f"当前第 {count} 条")
        count += 1
    # 结束任务
    browser.quit()
    
if __name__ == "__main__":
    soundcloud_index()

python pdb调试以及sublime3快捷键设置

sublime设置

sublime设置快捷键F5为运行,Ctrl+F5调试。就会对python调试方便很多。

  • Package Control中下载SublimeREPL(Read-Eval-Print-Loop)
  • 首选项 -> 按键绑定-用户 进行设置 

[
  {
    "keys": [
      "f5"
    ],
    "caption": "SublimeREPL: Python - RUN current file",
    "command": "run_existing_window_command",
    "args": {
      "id": "repl_python_run",
      "file": "config/Python/Main.sublime-menu"
    }
  },
  {
    "keys": [
      "ctrl+f5"
    ],
    "caption": "SublimeREPL: Python - PDB current file",
    "command": "run_existing_window_command",
    "args":
    {
        "id": "repl_python_pdb",
        "file": "config/Python/Main.sublime-menu"
    }
  }
]

pdb调试

c(continue): 继续执行,直到下一断点
w(where): 显示当前正在执行的代码行的上下文信息
a(args): 打印当前函数的参数列表
s(step): 执行当前代码行,并停在第一个能停的地方(相当于单步进入)
n(next): 继续执行到当前函数的下一行,或者当前行直接返回(单步跳过)
l(list): 列表,会打印出一个友好的总结,它能够显示出此刻你在代码中的位置
b(break): 动态添加断点,
q(quit): 结束

更多信息直接输入help查看

单步跳过(next)和单步进入(step)的区别在于, 单步进入会进入当前行调用的函数内部并停在里面, 而单步跳过会(几乎)全速执行完当前行调用的函数,并停在当前函数的下一行。

针对无限制滚动网站的采集

模拟滚动

from selenium import webdriver
from scrapy.selector import Selector
from selenium.webdriver.support.ui import WebDriverWait
browser = webdriver.Chrome() browser.get(url)
wait = WebDriverWait(browser, 10)
wait.until(lambda dr: dr.find_element_by_class_name('project-detail').is_displayed())

# 一直滚动到最底部
js1 = 'return document.body.scrollHeight'
js2 = 'window.scrollTo(0, document.body.scrollHeight)'
old_scroll_height = 0
while browser.execute_script(js1) >= old_scroll_height:
    old_scroll_height = browser.execute_script(js1)
    browser.execute_script(js2) 
    time.sleep(1)

接下里就可以进行采集了

使用python requests模块来发消息到钉钉自定义机器人webhook

# coding: utf-8

import json
import requests

def dingding_robot(data):
    dingding_robot_token = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx"

    headers = {'content-type': 'application/json'}
    r = requests.post(dingding_robot_token, headers=headers, data=json.dumps(data))
    r.encoding = 'utf-8'
    return (r.text)

if __name__ == "__main__":
    data = {
        "msgtype": "link", 
        "link": {
            "text":"群机器人是钉钉群的高级扩展功能。群机器人可以将第三方服务的信息聚合到群聊中,实现自动化的信息同步。", 
            "title": "自定义机器人", 
            "picUrl": "", 
            "messageUrl": "https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.Rqyvqo&treeId=257&articleId=105735&docType=1"
        }
    }
    res = dingding_robot(data)
    print (res)

Python实例:找第n个默尼森数

经典程序设计问题:找第n个默尼森数。P是素数且M也是素数,并且满足等式M=2**P-1,则称M为默尼森数。例如,P=5,M=2**P-1=31,5和31都是素数,因此31是默尼森数。


# -*- coding: utf-8 -*-
"""
Spyder zrex

This is a temporary script file.
"""

from math import sqrt

def is_prime(n):
    if n == 1:
        return False
    for i in range(2, int(sqrt(n))+1):
        if n % i == 0:
            return False
    return True

def is_monisen(n):
    m = 2 ** n - 1
    if is_prime(m):
        return True

if __name__ == "__main__":
    
    monisen = []
    for n in range(1,20):
        if is_prime(n):
            if is_monisen(n):
                monisen.append(2**n-1)
    print (monisen)

Python下安装Numpy、Scipy、Matlotlib等依赖库时需要面对的问题

ImportError: DLL load failed: 找不到指定的模块
ImportError: DLL load failed: The specified module could not be found

安装这些科学计算包,免不了要被多坑几次,这些原因是跟当前的python版本不兼容,多半是通过pip install package或者 easy_install install package 直接安装导致。

所以针对上面问题,最好先卸载之前的问题包,然后使用官方的地址,重新安装

卸载方式:pip uninstall package

然后下载官方包whl:

http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy
http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy
http://www.lfd.uci.edu/~gohlke/pythonlibs/#matplotlib

安装过程中最重要的地方就是版本需要兼容。其中cp27表示CPython 2.7版本,cp34表示CPython 3.4,win_amd64指的是64位版本。在官方顶部位置也有说明。

安装whl文件方法:pip install matplotlib-1.5.1-cp27-none-win_amd64.whl (pip安装whl文件的前提是要先安装wheel包:pip install wheel)


如何使用官方包还有啥问题,那就只能必杀技:套件安装:Anacondawinpython,使用之后整个人都变好了。


备注pip用法:

pip install numpy             --安装包numpy
pip uninstall numpy           --卸载包numpy
pip show --files PackageName  --查看已安装包
pip list outdated             --查看待更新包信息
pip install --upgrade numpy   --升级包
pip install -U PackageName    --升级包
pip search PackageName        --搜索包
pip help                      --显示帮助信息

python获取本机IP方法

python获取本机IP方法,记录下

import fcntl
import struct
import socket

def get_local_ip(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24]) 

local_ip = get_local_ip('eth0')

print local_ip