python itchat 文档里itchat 模块能实现什么有趣的东西

23158被浏览894581分享邀请回答3.5K77 条评论分享收藏感谢收起#!/usr/bin/env python
"""Send the contents of a directory as a MIME message."""
import sys
import smtplib
# For guessing MIME type based on file name extension
import mimetypes
from optparse import OptionParser
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
如果使用yagmail,发送一个带附件的邮件,只需要2行代码:import yagmail
yag = yagmail.SMTP(user='joy_', password='nicai?', host='', port='25')
yag.send(user, subject = "I now can send an attachment", attachments=['a.txt', 'b.jpg'])
2. requestsrequests很多人都推荐过了,不过可能一些同学感受不到requests到底好在哪里。我们就以官网的例子为例简单说明,在没有request之前,如果我们要请求,需要像下面这样:#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib2
gh_url = ''
req = urllib2.Request(gh_url)
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, gh_url, 'user', 'pass')
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)
urllib2.install_opener(opener)
handler = urllib2.urlopen(req)
print handler.getcode()
print handler.headers.getheader('content-type')
# 'application/json'
用requests以后,做同样的事情,我们可以这样(注意,前3行代码等于上面一整段代码):&&& r = requests.get('/user', auth=('user', 'pass'))
&&& r.status_code
&&& r.headers['content-type']
'application/ charset=utf8'
&&& r.encoding
&&& r.text
u'{"type":"User"...'
&&& r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
3. psutilpsutil是用来获取操作系统监控以及进程管理的,如果你正在写一个监控系统(或脚本),赶紧去试试。这么说吧,我曾经使用psutil把网易内部的一个监控模块,从1000+行重构到了100+行。我这里推荐的几个库,可能yagmail对最多人有用。而psutil,对专业的人士最有用。如果你要写一个监控系统,不使用psutil的话,只能直接去/proc目录下读取想用的文件进行计算,或者执行iostat、vmstat、df等linux命令获取命令输出,不管哪一种方法,都要处理很多繁琐的细节。有了psutil以后,就轻松多了。贴段代码大家感受一下:def get_network_info(self):
psutil.net_io_counters()
snetio(bytes_sent=, bytes_recv=, packets_sent=80164, packets_recv=88134, errin=0, errout=0,
dropin=0, dropout=0)
return psutil.net_io_counters()
def get_memory_used(self):
psutil.virtual_memory()
svmem(total=, available=, percent=10.5, used=,
free=, active=, inactive=, buffers=, cached=)
memory_info = psutil.virtual_memory()
memory_used = ( memory_info.total * memory_info.percent / 100 ) / 1024 / 1024
return memory_used
此外,使用越来越广泛的监控工具glances(如果没用过,要不现在就是试试?),就是用psutil收集相关数据的。4. BeautifulSoup如果你写爬虫,还在用XPath解析HTML,那赶紧用用BeautifulSoup,比XPath好用一百倍;如果你还在用正则表达式从HTML中获取内容,BeautifulSoup能让你好用到哭。(补充:评论里大家都说XPath更好用,难道是我思维方式和大家不一样?)BeautifulSoup是用来解析HTML的,特点就是好用,有人吐槽BeautifulSoup慢?我不在乎BeautifulSoup比XPath慢多少,我只知道,我的时间比机器的更宝贵。例如,要找到页面中所有的links,如下所示:from bs4 import BeautifulSoup
soup = BeautifulSoup(open("index.html"))
for link in soup.find_all('a'):
print(link.get('href'))
例如,我在编写知乎的爬虫的时候,对于每一个用户的”关注”页面,对于每一个关注对象,有如下的tag:&div class="zm-profile-card zm-profile-section-item zg-clear no-hovercard"&
&a title="天雨白" data-hovercard="p$t$tian-yu-bai" class="zm-item-link-avatar" href="/people/tian-yu-bai"&
所以,解析单个关注的用户代码如下所示: soup = BeautifulSoup(text)
#通过属性找到这个div,对于每个用户,对应于这样一个div
items = soup.find_all('div', class_="zm-profile-card zm-profile-section-item zg-clear no-hovercard")
for item in items:
# 获取这个div下的&a&标签的title属性
name = item.a.attrs['title']
# 获取这个div下的&a&标签下的&img&标签里面的src属性
= item.a.img.attrs['src']
有了BeautifulSoup以后,爬虫操作就变得特别简单了。脏活累活别人都帮忙做好了。5. utils除了开源的库以外,还有些开源项目的DataStruct.py helper.py utils.py文件,也值得看一看。里面很多好东西,都是可以直接拿过来用的。我举几个例子。requests中的CaseInsensitiveDict(),大家看名字就知道什么意思了,我就不多说了。# -*- coding: utf-8 -*-
requests.structures
~~~~~~~~~~~~~~~~~~~
Data structures that power Requests.
class CaseInsensitiveDict(dict):
"""Case-insensitive Dictionary
For example, ``headers['content-encoding']`` will return the
value of a ``'Content-Encoding'`` response header."""
1. low_keys是一个字典,key是dict中key的消息形式,大写是dict中的key
2. 如果对字典进行了修改操作,则清空low_keys
3. 获取字典时,通过get --& __getitem__ --& __contains__ --&
通过low_keys字典获取到真实的key,通过真实的key获取dict中的value
def lower_keys(self):
if not hasattr(self, '_lower_keys') or not self._lower_keys:
self._lower_keys = dict((k.lower(), k) for k in self.iterkeys())
return self._lower_keys
def _clear_lower_keys(self):
if hasattr(self, '_lower_keys'):
self._lower_keys.clear()
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
self._clear_lower_keys()
def __delitem__(self, key):
dict.__delitem__(self, key)
self._lower_keys.clear()
def __contains__(self, key):
return key.lower() in self.lower_keys
def __getitem__(self, key):
# We allow fall-through here, so values default to None
if key in self:
return dict.__getitem__(self, self.lower_keys[key.lower()])
def get(self, key, default=None):
if key in self:
return self[key]
return default
def main():
d = CaseInsensitiveDict()
d['Laimingxing'] = 'Laimingxing'
d['LAimingxing'] = 'LAimingxing'
print d['LAimingxing']
if __name__ == '__main__':
werkzeug中的LocalProxy、ImmutableList、ImmutableDict(),其中ImmutableList和ImmutableDict大家一看就知道是什么意思,这里要说的是LocalProxy,使用LocalProxy,分分钟实现代理模式。web.py的utils.py中各个函数和类都值得看一看(),不但可以了解好用的函数和数据结构,而且,还能够学习一下高手的Python代码。例如:def dictreverse(mapping):
Returns a new dictionary with keys and values swapped.
&&& dictreverse({1: 2, 3: 4})
{2: 1, 4: 3}
return dict([(value, key) for (key, value) in iteritems(mapping)])
def dictfind(dictionary, element):
Returns a key whose value in `dictionary` is `element`
or, if none exists, None.
&&& d = {1:2, 3:4}
&&& dictfind(d, 4)
&&& dictfind(d, 5)
for (key, value) in iteritems(dictionary):
if element is value:
return key
class Storage(dict):
A Storage object is like a dictionary except `obj.foo` can be used
in addition to `obj['foo']`.
&&& o = storage(a=1)
&&& o['a']
&&& o.a = 2
&&& o['a']
&&& del o.a
Traceback (most recent call last):
AttributeError: 'a'
def __getattr__(self, key):
return self[key]
except KeyError as k:
raise AttributeError(k)
def __setattr__(self, key, value):
self[key] = value
def __delattr__(self, key):
del self[key]
except KeyError as k:
raise AttributeError(k)
def __repr__(self):
return '&Storage ' + dict.__repr__(self) + '&'
ps:web.py的作者是亚伦·斯沃茨(Aaron Swartz),一位年少成名的计算机天才,著名社交网站联合创始人。致力于网络信息开放,却因涉嫌非法侵入麻省理工学院(MIT)和JSTOR(全称Journal Storage,存储学术期刊的在线系统)被指控,将受到最高35年监禁和100万美元罚款。该案正在认罪辩诉阶段,而亚伦·斯沃茨却于日在其纽约布鲁克林的寓所内,用一根皮带上吊自杀,尸体随后被女友发现,年仅26岁。当然,我这还有很多乱七八糟的好东西,如果大家感兴趣的话,我再补充吧。要学Python看这里:此外,大家反馈,这个回答也对大家很有帮助:61649 条评论分享收藏感谢收起查看更多回答&img src=&/50/v2-8f9db41dfd5d_b.png& data-rawwidth=&3000& data-rawheight=&998& class=&origin_image zh-lightbox-thumb& width=&3000& data-original=&/50/v2-8f9db41dfd5d_r.png&&&p&现在绝大多数同学都在使用微信,不过微信有很多限制,比如:&/p&&ol&&li&微信聊天记录只保存在本地,换个手机那些内容就找不到了&/li&&li&微信扫码加群人数有限制,超过100个就得先加群聊成员微信再由其拉进去,很不方便&/li&&/ol&&p&很早就有想法把我的那些技术交流群也转移到微信上,不过当时想了想人工操作的成本太高作罢了。&/p&&p&但自从ItChat(一个网页版微信(&a href=&/?target=http%3A//& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&)的SDK)诞生以来,开发者有了和微信交互的机会,再之后出现了wxpy项目,开发者可以很方便的实现一些微信机器人之类的项目了。有一天刷到一个「Python 里itchat 模块能实现什么有趣的东西?」问题,然后回写了「&a href=&/question//answer/& class=&internal&&申请加好友或者和好友聊天时带某个暗语,可以把你拉群,发现群满了之后自动创建群再把你拉入&/a&」的小例子。&/p&&p&我写新的项目都会尝鲜,换用更多的技术栈,尝试更多的技术选型。之前一直写React+Material-UI+Mobx这样的组合,Vue也只是在豆瓣电影的 &a href=&/?target=https%3A///tag/%23/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&选影视&i class=&icon-external&&&/i&&/a& 上用到,就想着继续深入Vue,再用用Element-ui吧。另外对SSE和Redis的ORM库也想尝试下,上个月提上日程,做成了你们将要看到的Web端的微信管理系统,地址是 &a href=&/?target=https%3A///dongweiming/wechat-admin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dongweiming/wechat-admin&i class=&icon-external&&&/i&&/a&。&/p&&p&首图就是这个后台的效果拼起来的。由于安全考虑我就不提供demo地址了,不过大家可以通过下面的一个短视频跟我登录感受一下(?ω?) :&/p&&p&&br&&/p&&a class=&video-box& href=&/?target=https%3A///video/326208& target=&_blank& data-video-id=&& data-video-playable=&true& data-name=&& data-poster=&/v2-7b60573cffee1c10b08bd.jpg& data-lens-id=&326208&&
&img class=&thumbnail& src=&/v2-7b60573cffee1c10b08bd.jpg&&&span class=&content&&
&span class=&title&&&span class=&z-ico-extern-gray&&&/span&&span class=&z-ico-extern-blue&&&/span&&/span&
&span class=&url&&&span class=&z-ico-video&&&/span&/video/326208&/span&
&p&&br&&/p&&h2&&b&功能列表&/b&&/h2&&ul&&li&支持显示好友列表,可过滤&/li&&li&支持显示群聊列表,可过滤&/li&&li&可以同时给多个用户/群聊成员发送消息,支持发送文件,emoji表情。可预览&/li&&li&如果为群聊创建者,可以删除(多个)成员&/li&&li&可以选择好友/群聊成员创建新群&/li&&li&对自动建群、加群关键词、邀请文本等可配置&/li&&li&永久保存消息,可以通过消息列表页面查看和过滤。接收消息进程停止自动重启&/li&&li&支持消息提醒&/li&&li&支持发送加群聊成员好友请求&/li&&li&自动添加联系人,拉对方入群,群满之后自动创建新群&/li&&li&支持灵活的插件系统,内置图灵机器人、ChatterBot、Simsimi等插件&/li&&li&可以指定公众号,当公众号发布文章后自动转发到指定的群聊里&/li&&li&群成员可发起投票踢人,可以灵活的设置投票规则&/li&&/ul&&h2&&b&用的技术和库&/b&&/h2&&p&&b&前端&/b&&/p&&p&Vue+Axios+Element-ui+Vue-cli&/p&&p&&b&后端&/b&&/p&&p&Flask+Celery+SSE+&a href=&/?target=https%3A///coleifer/walrus& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Walrus&i class=&icon-external&&&/i&&/a&+Gunicorn+Flask-Migrate+Flask-SQLAlchemy+&a href=&/?target=https%3A///dongweiming/ItChat& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ItChat&i class=&icon-external&&&/i&&/a&(Fork版本)+&a href=&/?target=https%3A///dongweiming/wxpy& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Wxpy&i class=&icon-external&&&/i&&/a&(Fork版本)+PyMySQL&/p&&p&注意本项目只支持Python 3 !&/p&&h2&&b&插件&/b&&/h2&&p&目前自带了4个插件:&/p&&ul&&li&Simsimi 也就是当年的小黄鸡。默认未开启&/li&&li&Help帮助插件,根据所有插件的description属性的内容生成&/li&&li&Tuling图灵机器人,@群主即可开聊&/li&&li&Chatter基于机器学习的ChatterBot 和群主私聊&/li&&/ul&&p&另外提供docker compose的方式让你快速部署应用。&/p&&p&欢迎star: &a href=&/?target=https%3A///dongweiming/wechat-admin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dongweiming/wechat-admin&i class=&icon-external&&&/i&&/a& 和使用,如果你有更多有意思的想法和功能欢迎提交PR和Issue,另外也可以贡献更多的&a href=&/?target=https%3A///dongweiming/wechat-plugins& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&插件&i class=&icon-external&&&/i&&/a&&/p&&p&如果你对本项目有兴趣,可以加 Sanic(微信号python-org)入群感受,也可直接扫描如下二维码加我,如果验证信息中包含 python 可以直接进群,否则可以和Py之美私聊进群, 可打开项目链接进群:&/p&&p&&br&&/p&&p&&a href=&/?target=https%3A///dongweiming/wechat-admin/raw/master/screenshots/chat.png& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/dongweiming/&/span&&span class=&invisible&&wechat-admin/raw/master/screenshots/chat.png&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&p&&b&注:之前的Py之美(微信号pythonorg)被暂时封禁了。&/b&&/p&&p&另外最近一段时间我将在微信公众号「Python之美」(微信号python_cn)中介绍这个项目技术选型,实现,走过的一些坑,还有Vue等相关的一些内容,欢迎关注。&/p&
现在绝大多数同学都在使用微信,不过微信有很多限制,比如:微信聊天记录只保存在本地,换个手机那些内容就找不到了微信扫码加群人数有限制,超过100个就得先加群聊成员微信再由其拉进去,很不方便很早就有想法把我的那些技术交流群也转移到微信上,不过当…
&img src=&/50/bdbf8a7bcc80865efa9371ea_b.jpg& data-rawwidth=&338& data-rawheight=&220& class=&content_image& width=&338&&&h1&Python黑客编程3网络数据监听和过滤&/h1&&br&&p&
课程的实验环境如下:&/p&&p&o
操作系统:kali Linux 2.0&/p&&p&o
编程工具:Wing IDE&/p&&p&o
Python版本:2.7.9&/p&&p&o
涉及到的主要python模块:pypcap,dpkt,scapy,scapy-http&/p&&p&涉及到的几个python网络抓包和分析的模块,dpkt和scapy在kali linux 2.0 中默认已经被安装,如果你的系统中没有需要手动安装一下,下面是软件包安装的简单说明。&/p&&p&在kali下安装pypcap需要两步(如果在其他系统上可能还需要安装python-dev):&/p&&br&&p&apt-get install libpcap-dev&/p&&p&pip install pypcap&/p&&br&&img src=&/50/b0ebb20bde_b.png& data-rawwidth=&715& data-rawheight=&375& class=&origin_image zh-lightbox-thumb& width=&715& data-original=&/50/b0ebb20bde_r.png&&&br&&p&
使用pip安装scapy。&/p&&br&&p&root@kali:/home/pycharm# pip install scapy&/p&&br&&img src=&/50/dc6c0fda7ae260bbd38f84_b.png& data-rawwidth=&742& data-rawheight=&108& class=&origin_image zh-lightbox-thumb& width=&742& data-original=&/50/dc6c0fda7ae260bbd38f84_r.png&&&p&使用pip安装scapy-http。&/p&&br&&p&root@kali:/home/pycharm# pip install scapy-http&/p&&br&&img src=&/50/c08c797be2a0afc6fa1fec_b.png& data-rawwidth=&734& data-rawheight=&315& class=&origin_image zh-lightbox-thumb& width=&734& data-original=&/50/c08c797be2a0afc6fa1fec_r.png&&&p&基础环境准备好之后,我还要再唠叨一下你必须要掌握的基础。&/p&&br&&h2&1.1
技术没有黑白,网络编程的基础是协议&/h2&&br&&p&把编程挂上黑客的名义,多少有些标题党。代码怎么写,程序怎么用,完全是技术问题。不会因为叫网络编程就低人一等,叫黑客编程也不会变得神秘或者高大上,代码就在那里,不卑微也不高尚。所以学习编程,要有颗平常心。&/p&&p&很多听课的同学和我反应,网络编程格外的吃力,繁琐,要实现某种功能,如果Google不到类似的代码就无法下手。各种语言或者框架针对网络编程的实现基本都相同,因为我们接触到网络通信都基于统一的规范和标准,语言和框架只是在用自己的方式去描述这个规范而已。本质的问题来了,如果你连基本的网络通信的四层模型都不懂,对TCP/IP协议族毫无概念,那么我奉劝你先不要着急敲代码,找本书,打开WireShark这样的工具好好做做练习。&/p&&p&本次课程中的所有案例,其实都在遵循一个基本的思路(其他网络通信场景类似):&/p&&p&初始化以太网数据包对象à以太网数据包分离出ip数据包àIP数据包分离传输层数据包à传输层数据包分离应用层数据包。&/p&&p&只要我们具备基础的网络知识,结合程序中各个对象提供的字段就能得到我们想要的任何基础信息,在此基础上做些信息处理就能完成大部分网络监听和数据处理的任务。附上几幅图,如果这方面有欠缺的话,请立即去充电吧!&/p&&img src=&/50/65a6b4ffb27a8e17e0ffa8_b.jpg& data-rawwidth=&490& data-rawheight=&442& class=&origin_image zh-lightbox-thumb& width=&490& data-original=&/50/65a6b4ffb27a8e17e0ffa8_r.jpg&&&p&以太网帧格式&/p&&img src=&/50/7a4e045d500b0b2c834d0d_b.jpg& data-rawwidth=&490& data-rawheight=&253& class=&origin_image zh-lightbox-thumb& width=&490& data-original=&/50/7a4e045d500b0b2c834d0d_r.jpg&&&img src=&/50/3c878bd51f_b.jpg& data-rawwidth=&691& data-rawheight=&249& class=&origin_image zh-lightbox-thumb& width=&691& data-original=&/50/3c878bd51f_r.jpg&&&p&Tcp数据包格式&/p&&br&&h2&1.2
使用PYPCAP实时抓包&/h2&&br&&p&pypcap进行实时的数据包捕获,使用上很简单,我们先看一小段示例代码:&/p&&br&&div class=&highlight&&&pre&&code class=&language-python&&&span&&/span&&span class=&kn&&import&/span& &span class=&nn&&pcap&/span&
&span class=&n&&pc&/span&&span class=&o&&=&/span&&span class=&n&&pcap&/span&&span class=&o&&.&/span&&span class=&n&&pcap&/span&&span class=&p&&(&/span&&span class=&s1&&'wlan0'&/span&&span class=&p&&)&/span&
&span class=&c1&&#注,参数可为网卡名,如eth0&/span&
&span class=&n&&pc&/span&&span class=&o&&.&/span&&span class=&n&&setfilter&/span&&span class=&p&&(&/span&&span class=&s1&&'tcp port 80'&/span&&span class=&p&&)&/span&
&span class=&c1&&#2.设置监听过滤器&/span&
&span class=&k&&for&/span& &span class=&n&&ptime&/span&&span class=&p&&,&/span&&span class=&n&&pdata&/span& &span class=&ow&&in&/span& &span class=&n&&pc&/span&&span class=&p&&:&/span&
&span class=&c1&&#ptime为收到时间,pdata为收到数据&/span&
&span class=&k&&print&/span& &span class=&n&&ptime&/span&&span class=&p&&,&/span&&span class=&n&&pdata&/span&
&span class=&c1&&#...&/span&
&/code&&/pre&&/div&&br&&p&在上面的代码中,我们通过“import pcap”首先引入pypcap包,然后初始化一个pcap类实例,构造函数需要传入一个网卡用来监听,我们可以通过ifconfig获取当前机器上的网卡。&/p&&p&pcap类的setfilter方法用来设置监听过滤条件,这里我们设置过滤的数据包为tcp协议80端口的数据。之后程序就进入监听状态了。&/p&&p&接下来我们循环输出接收到的数据,ptime为时间,pdata的数据,默认数据打印为ascii字符,效果如下:&/p&&img src=&/50/4d1de019fcdbc007442bea90a1d5e031_b.png& data-rawwidth=&784& data-rawheight=&261& class=&origin_image zh-lightbox-thumb& width=&784& data-original=&/50/4d1de019fcdbc007442bea90a1d5e031_r.png&&&p&在抓到数据包之后,下一步就需要对数据进行解析,这里我们引入dpkt组件包。&/p&&br&&h2&1.3
使用DPKT 解析数据包&/h2&&br&&p&dpkt,简单来说是一个数据包解析工具,可以解析离线/实时pcap数据包。&/p&&br&&h3&1.3.1 实时解析&/h3&&br&&p&我们以下面的代码为例,讲解基本应用。&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import pcap
import dpkt
def captData():
pc=pcap.pcap('wlan0')
#注,参数可为网卡名,如eth0
pc.setfilter('tcp port 80')
#设置监听过滤器
for ptime,pdata in pc:
#ptime为收到时间,pdata为收到数据
anlyCap(pdata);
def anlyCap(pdata):
p=dpkt.ethernet.Ethernet(pdata)
if p.data.__class__.__name__=='IP':
ip='%d.%d.%d.%d'%tuple(map(ord,list(p.data.dst)))
if p.data.data.__class__.__name__=='TCP':
if p.data.data.dport==80:
print p.data.data.data # http 请求的数据
captData();
&/code&&/pre&&/div&&br&&p&在上面代码中,我们首先导入dpkt包。这段代码中新增了一个anlyCap方法,该方法接收由pcap捕获的http数据包,然后先取得ip数据报文,从ip报文中再提取tcp数据包,最后从tcp数据包中提取http请求的数据,将其打印出来。&/p&&img src=&/50/6a6d6ce8e9cf5fb878906_b.png& data-rawwidth=&989& data-rawheight=&488& class=&origin_image zh-lightbox-thumb& width=&989& data-original=&/50/6a6d6ce8e9cf5fb878906_r.png&&&p&对于数据包的分析,新手可能会感到迷茫,如何选择合适的协议和方法来分析呢?这个问题的答案不在代码,而在于网络通信协议本身的掌握和理解。&/p&&p&回到上面的代码,我们想要分析http请求的数据,http是应用层协议,通过TCP协议来传输数据,那么TCP数据又被封装在IP数据报文中。使用dpkt的第一步就是选择数据包类型,这里当然是要选择以太网数据包了。&/p&&img src=&/50/25c082d606fb5cef48599b_b.png& data-rawwidth=&318& data-rawheight=&230& class=&content_image& width=&318&&&p&按照网络协议,层层剥离,会解析到所有你想要的数据。&/p&&img src=&/50/70e8b8f9ea95fc3a498c1260_b.png& data-rawwidth=&330& data-rawheight=&156& class=&content_image& width=&330&&&br&&h3&1.3.2 解析离线数据包&/h3&&br&&p&下面我们来看一个解析离线数据包的例子。&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import dpkt
import socket
#----------------------------------------------------------------------
def printPcap(pcap):
for(ts,buf) in pcap:
eth=dpkt.ethernet.Ethernet(buf);
src=socket.inet_ntoa(ip.src);
dst=socket.inet_ntoa(ip.dst);
tcp=ip.#tcp.dport
print '[+]Src: '+src+ ' ---&Dst: '+ dst
#----------------------------------------------------------------------
def main():
f=open('/home/pcap/test.pcap');#1.open file
pcap=dpkt.pcap.Reader(f);# init pcap obj
printPcap(pcap);
if __name__ == '__main__':
&/code&&/pre&&/div&&br&&p&
首先我准备了一个测试的抓包文件—test.pcap,该文件是我使用wireshark在windows上抓取的数据包,现在使用代码对齐进行基本的分析。在方法printPcap中,获取ip数据报的内容,然后获取它的源ip和目标ip数据,通过socket.inet_ntoa方法转换成ip字符串,最后打印出来。结果如下图所示:&/p&&img src=&/50/c1a89ec6cffe3_b.png& data-rawwidth=&535& data-rawheight=&344& class=&origin_image zh-lightbox-thumb& width=&535& data-original=&/50/c1a89ec6cffe3_r.png&&&br&&h2&1.4 使用SCAPY进行数据监听&/h2&&br&&p&Scapy的是一个强大的交互式数据包处理程序(使用python编写)。它能够伪造或者解码大量的网络协议数据包,能够发送、捕捉、匹配请求和回复包等等。它可以很容易地处理一些典型操作,比如端口扫描,tracerouting,探测,单元 测试,攻击或网络发现(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。 最重要的他还有很多更优秀的特性——发送无效数据帧、注入修改的802.11数据帧、在WEP上解码加密通道(VOIP)、ARP缓存攻击(VLAN) 等,这也是其他工具无法处理完成的。&/p&&p&Scapy可以单独使用,也可以在python中调用。&/p&&br&&h3&1.4.1 Scapy基本使用&/h3&&br&&p&了解Scapy的基本使用和支持的方法,首先我们从终端启动scapy,进入交互模式。&/p&&img src=&/50/fd07c63eced7c1_b.png& data-rawwidth=&707& data-rawheight=&187& class=&origin_image zh-lightbox-thumb& width=&707& data-original=&/50/fd07c63eced7c1_r.png&&&p&ls()显示scapy支持的所有协议。&/p&&img src=&/50/5b6f9501550cfd2de3c4d7_b.png& data-rawwidth=&688& data-rawheight=&422& class=&origin_image zh-lightbox-thumb& width=&688& data-original=&/50/5b6f9501550cfd2de3c4d7_r.png&&&p&ls()函数的参数还可以是上面支持的协议中的任意一个的类型属性,也可以是任何一个具体的数据包,如ls(TCP),ls(newpacket)等。&/p&&img src=&/50/cdcd1bb2c3e_b.png& data-rawwidth=&467& data-rawheight=&229& class=&origin_image zh-lightbox-thumb& width=&467& data-original=&/50/cdcd1bb2c3e_r.png&&&p&lsc()列出scapy支持的所有的命令。&/p&&img src=&/50/26eca691afcb4ea_b.png& data-rawwidth=&731& data-rawheight=&409& class=&origin_image zh-lightbox-thumb& width=&731& data-original=&/50/26eca691afcb4ea_r.png&&&p&本篇文章使用的只是scapy众多命令中的一个,sniff。&/p&&p&conf:显示所有的配置信息。conf变量保存了scapy的配置信息。&/p&&img src=&/50/0646cbc6c47db44bbac9_b.png& data-rawwidth=&747& data-rawheight=&448& class=&origin_image zh-lightbox-thumb& width=&747& data-original=&/50/0646cbc6c47db44bbac9_r.png&&&br&&p&help()显示某一命令的使用帮助,如help(sniff)。&/p&&img src=&/50/81f9da0ffbd7d_b.png& data-rawwidth=&728& data-rawheight=&449& class=&origin_image zh-lightbox-thumb& width=&728& data-original=&/50/81f9da0ffbd7d_r.png&&&br&&p&show()显示指定数据包的详细信息。例如,这里我们先创建一个IP数据包,然后调用show方法。&/p&&img src=&/50/bf2c4bdfa5d0b_b.png& data-rawwidth=&293& data-rawheight=&328& class=&content_image& width=&293&&&p&sprintf()输出某一层某个参数的取值,如果不存在就输出”??”,具体的format格式是:%[[fmt][r],][layer[:nb].]field%,详细的使用参考&Security Power Tools&的146页。&/p&&p&%[[fmt][r],][layer[:nb].]field%&/p&&p&layer:协议层的名字,如Ether、IP、Dot11、TCP等。&/p&&p&filed:需要显示的参数。&/p&&p&nb:当有两个协议层有相同的参数名时,nb用于到达你想要的协议层。&/p&&p&r:是一个标志。当使用r标志时,意味着显示的是参数的原始值。例如,TCP标志中使用人类可阅读的字符串’SA’表示SYN和ACK标志,而其原始值是18.&/p&&img src=&/50/1fa98eff465_b.png& data-rawwidth=&647& data-rawheight=&469& class=&origin_image zh-lightbox-thumb& width=&647& data-original=&/50/1fa98eff465_r.png&&&br&&h3&1.4.2
sniff&/h3&&br&&p&Scapy的功能如此强大,足够写个系列了,本文只关注sniff这一个方法。&/p&&p&sniff方法是用来嗅探数据的,我们首先使用help查看一下此方法的使用说明:&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sniff(count=0, store=1, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, *arg, **karg)
Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -& list of packets
count: number of packets to capture. 0 means infinity
store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
opened_socket: provide an object ready to use .recv() on
stop_filter: python function applied to each packet to determine
if we have to stop the capture after this packet
ex: stop_filter = lambda x: x.haslayer(TCP)
&/code&&/pre&&/div&&br&&p&除了上面介绍的几个参数,sniff()函数还有一个重要的参数是filter,用来表示想要捕获数据包类型的过滤器,如只捕获ICMP数据包,则filter=”ICMP”;只捕获80端口的TCP数据包,则filter=”TCP and (port 80)”。其他几个重要的参数有:count表示需要不活的数据包的个数;prn表示每个数据包处理的函数,可以是lambda表达式,如prn=lambda x:x.summary();timeout表示数据包捕获的超时时间。&/p&&br&&p&sniff(filter=&icmp and host 66.35.250.151&, count=2)&/p&&br&&p&这段代码过滤icmp协议,host地址为66.35.250.151,捕获数据包个数为2个。&/p&&br&&p&sniff(iface=&wifi0&, prn=lambda x: x.summary())&/p&&br&&p&这段代码绑定网卡wifi0,对捕获的数据包使用summary进行数据汇总。&/p&&br&&p&sniff(iface=&eth1&, prn=lambda x: x.show())&/p&&br&&p&这段代码绑定网卡eth1,对数据包调用show方法,显示基本信息。&/p&&p&下面我们看具体的一段代码:&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&from scapy.all import *
ap_list = []
def PacketHandler(pkt) :
if pkt.haslayer(Dot11) :
if pkt.type == 0 and pkt.subtype == 8 :
if pkt.addr2 not in ap_list :
ap_list.append(pkt.addr2)
print &AP MAC: %s with SSID: %s & %(pkt.addr2, )
sniff(iface=&wlan0mon&, prn = PacketHandler)
&/code&&/pre&&/div&&br&&p&上面这段代码对绑定网卡WLAN0mon,对每个数据包调用PacketHandler方法进行解析。PacketHandler实际上是通过数据包过滤可访问的无线网络的SSID。&/p&&br&&h3&1.4.3 Scapy-http&/h3&&br&&p&Scapy-http直接将 数据包格式化成 http数据信息,免去自己构建http数据结构进行解析的麻烦。&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import scapy_http.http as HTTP
from scapy.all import *
from scapy.error import Scapy_Exception
def pktTCP(pkt):
global count
count=count+1
print count
if HTTP.HTTPRequest or HTTP.HTTPResponse in pkt:
src=pkt[IP].src
srcport=pkt[IP].sport
dst=pkt[IP].dst
dstport=pkt[IP].dport
test=pkt[TCP].payload
if HTTP.HTTPRequest in pkt:
#print &HTTP Request:&
#print test
print &======================================================================&
if HTTP.HTTPResponse in pkt:
print &HTTP Response:&
headers,body= str(test).split(&\r\n\r\n&, 1)
print headers
except Exception,e:
print &======================================================================&
#print pkt[IP].src,pkt[IP].sport,'-&',pkt[TCP].flags
print 'other'
sniff(filter='tcp and port 80',prn=pktTCP,iface='wlan0')
&/code&&/pre&&/div&&br&&p&上面的这段代码,我们引入scapy_http.http,该组件包可以直接将Http请求的TCP数据包格式化成HTTPRequest或者HTTPResponse对象,这大大方便了我们对HTTP数据的分析。&/p&&p&o
scapy_http在github上的开源地址为:&a href=&/?target=https%3A///invernizzi/scapy-http& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/invernizzi/s&/span&&span class=&invisible&&capy-http&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&。&/p&&p&1.4.4
综合实例--net-creds&/p&&p&net-creds是一个小的开源程序,由python编写,主要是从网络或者pcap中嗅探敏感数据。可以嗅探以下类型的数据:&/p&&p&·
URLs visited&/p&&p&·
POST loads sent&/p&&p&·
HTTP form logins/passwords&/p&&p&·
HTTP basic auth logins/passwords&/p&&p&·
HTTP searches&/p&&p&·
FTP logins/passwords&/p&&p&·
IRC logins/passwords&/p&&p&·
POP logins/passwords&/p&&p&·
IMAP logins/passwords&/p&&p&·
Telnet logins/passwords&/p&&p&·
SMTP logins/passwords&/p&&p&·
SNMP community string&/p&&p&·
NTLMv1/v2 all supported protocols like HTTP, SMB, LDAP, etc&/p&&p&·
Kerberos&/p&&p&基本用法如下:&/p&&p&自动选择网卡进行嗅探:&/p&&br&&p&sudo python net-creds.py&/p&&br&&p&指定嗅探的网卡:&/p&&br&&p&sudo python net-creds.py -i eth0&/p&&br&&p&忽略指定IP的数据包:&/p&&br&&p&sudo python net-creds.py -f 192.168.0.2&/p&&br&&p&从pcap文件中过滤信息:&/p&&br&&p&python net-creds.py -p pcapfile&/p&&br&&p&建议读者能够静下心来阅读该程序的源码,本身并不是很复杂,难度不高。下面摘几段代码。&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span& ipr = Popen(['/sbin/ip', 'route'], stdout=PIPE, stderr=DN)
for line municate()[0].splitlines():
if 'default' in line:
l = line.split()
iface = l[4]
return iface
&/code&&/pre&&/div&&br&&p&上面这一段代码是利用Popen组件和PIPE组件来自动查找网卡。&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def telnet_logins(src_ip_port, dst_ip_port, load, ack, seq):
Catch telnet logins and passwords
global telnet_stream
msg = None
if src_ip_port in telnet_stream:
# Do a utf decode in case the client sends telnet options before their username
# No one would care to see that
telnet_stream[src_ip_port] += load.decode('utf8')
except UnicodeDecodeError:
# \r or \r\n or \n terminate commands in telnet if my pcaps are to be believed
if '\r' in telnet_stream[src_ip_port] or '\n' in telnet_stream[src_ip_port]:
telnet_split = telnet_stream[src_ip_port].split(' ', 1)
cred_type = telnet_split[0]
value = telnet_split[1].replace('\r\n', '').replace('\r', '').replace('\n', '')
# Create msg, the return variable
msg = 'Telnet %s: %s' % (cred_type, value)
printer(src_ip_port, dst_ip_port, msg)
del telnet_stream[src_ip_port]
# This part relies on the telnet packet ending in
# &login:&, &password:&, or &username:& and being &750 chars
# Haven't seen any false+ but this is pretty general
# might catch some eventually
# maybe use dissector.py telnet lib?
if len(telnet_stream) & 100:
telnet_stream.popitem(last=False)
mod_load = load.lower().strip()
if mod_load.endswith('username:') or mod_load.endswith('login:'):
telnet_stream[dst_ip_port] = 'username'
elif mod_load.endswith('password:'):
telnet_stream[dst_ip_port] = 'password'
&/code&&/pre&&/div&&br&&p&上面的代码是过滤telnet用户名和密码。首先对数据流就行utf-8解码,然后按照telnet协议对字符串进行分割和搜索,从而获取登录信息。&/p&&br&&h2&1.5
小结&/h2&&br&&p&本篇文章是对我之前在CSDN做的一次公开课的总结。没有深入讲解网络数据监听和分析的技术内容,介绍了Python中相关的组件,这样读者可以快速入门。&/p&&p& 安全感兴趣的,加qq群:hacking-1群:,hacking-2群:. 更多原创博文,会在我的微信号持续发布,请扫描下方二维码关注。&/p&&img src=&/50/ee46782d7bca34d682a4_b.jpg& data-rawwidth=&300& data-rawheight=&300& class=&content_image& width=&300&&
Python黑客编程3网络数据监听和过滤 课程的实验环境如下:o 操作系统:kali Linux 2.0o 编程工具:Wing IDEo Python版本:2.7.9o 涉及到的主要python模块:pypcap,dpkt,scapy,scapy-http涉及到的几个python网络抓包和分析的模块,dpkt和scapy…
&p&我是真正零基础开始学Python的,从一开始的一窍不通,到3个月后成功搭建了一个动态网站(没有用任何框架)。相比于计算机大牛,我更加知道一个小白将会遇到什么坑,遇到哪些难点。我把我的学习过程写在下面,并附上在每个阶段的学习资料,希望对零基础的Python学习者有所帮助。&/p&&p&注:本文只做经历分享,不是技术探讨。&/p&&p&&i&---&/i&&/p&&br&&p&在知乎上常常看到想要转行IT,或者是想学习编程但不知如何开始的朋友。回答这类问题的人往往只是列出书单资源然后给出一个大致的方向。有些朋友一开始就扎入了理论学习的汪洋大海,从苦读类似《算法导论》开始,能够坚持读下来的寥寥无几,学习的积极性也被不断的挫败感消磨的所剩无几。&/p&&br&&p&一直以来,编程对我而言是一种「黑魔法」般的存在。去年阿里月饼门,当很多人都参与到是非之争的时候,我更加着迷于程序员区区几行代码的脚本所展现出的威力,对于外行而言,这是超乎他们想象之外的某种能力——为什么我守在电脑面前盯着秒针然后拼命点击鼠标都不一定能抢到的礼物,程序员只需要提前花5分钟写3行代码就轻松搞定?&/p&&br&&p&所以,我的心底深处一直都想变成这样的一位魔法师。去年的8月,刚好工作上想要开发一个基于微信的英语学习网站,借此机会,我决定好好学习一下编程。在此之前,我所有关于程序的知识仅仅来源于两部分,一是本科时期的C语言必修课,现在已经忘的一干二净,不过好歹我从中明白编程是怎么回事;第二部分是大概两年前由于工作关系学的一些Python,不过只是皮毛,现在忘的七七八八。&/p&&br&&p&简单说,我的目标是建立一个网站,不过这个网站是动态的,也就是说它能识别谁登陆,然后对不同的人显示不同的内容。而当时的现实是,我完全不明白网页是如何显示出来的?譬如每个人登陆知乎的时候看到的是定制化的页面,后台是如何基于每个ID来组织出不同的页面的?所有我们看到的问题,回答,参与的评论在背后的服务器上是以一种什么样的形式存在的?又比如为什么有些页面只能在微信端打开,在电脑上就会出错?(不知道你有没有发现这一点)&/p&&br&&p&当时我的心中充满了无数个类似的问号?当然如果你也是小白,一定有着同样的疑问。好处是一开始就明确了学习的目的:Web建站。所以我的学习方案基本就是通过做项目学习,哪里不懂就解决哪里,边做边学习,不断推进。另外,由于知道很多成功的网站在用Python做服务器开发,比如知乎,所以我就自然选择了Python。
&/p&&br&&p&于是我就开始了我充满着挫败感和成就感的编程之路……&/p&&br&&p&从去年8月到12月的四个月里,除去本来的工作,为了学习质量,我会保证平均每天4个小时的学习时间,周末也不例外。另外,所有的文档,问答都尽量看英文的,这可以帮你剩下大量的时间。12月13日,我做的网站上线了,3天时间大概有5000人访问了这个网站,我有时在后台看着日志,不免有些心潮喷涌,我想把自己的经验写下来,希望对于那些有心学习编程但无从下手的朋友提供一些帮助和鼓励。
&/p&&h2&1. 我的自学编程之路&/h2&&p&1)基础
&/p&&p&刚开始的时候,我对搭建网站一无所知。为了给自己迅速建立一个框架,我在Google上面泡了整整一天,了解了HTML,CSS,JavaScript,Ajax,jQuery,React,SQL,服务器脚本等等知识,不求精通,只是了解每一项技术是干嘛的,另一方面建立起了一个学习的roadmap,这样大概知道做一个Web App需要哪些知识,分别学习的主次顺序。重点推荐两个资源:&/p&&p&Python基础知识:&a href=&///?target=https%3A//learnpythonthehardway.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Learn Python the Hard Way&i class=&icon-external&&&/i&&/a&&/p&&p&Web App基础知识:@张秋怡的&a href=&/question//answer/& class=&internal&&答案&/a&写的通俗易懂,极力推荐。&/p&&p&有了这个roadmap,我明白了前端三大必须掌握技能HTML,CSS和JavaScript,花了大概10天左右把W3Schools上的教程全部过了一遍,然后试着写了几个网页,感觉自己写的很没有底气。于是根据知乎和豆瓣上的推荐,买了《JaveScript DOM》和《Head First HTML与CSS》,边看书边把例子过了一遍。&/p&&p&W3Schools: &a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&/&i class=&icon-external&&&/i&&/a&&/p&&p&JavaScript:&a href=&///?target=https%3A///subject/1921890/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JavaScript DOM编程艺术&i class=&icon-external&&&/i&&/a&&/p&&p&HTML & CSS : &a href=&///?target=https%3A///subject//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Head First HTML与CSS(第2版)&i class=&icon-external&&&/i&&/a&&/p&&br&&p&前端是需要慢慢学习的,在看完上面的资料后,虽然能写出来一些挺漂亮的页面,但是我自己知道很多都是不符合标准的,更不要说代码风格什么的。这只能通过不断地积累和增加代码量来提高。由于明白服务器端需要耗费自己大量的时间,所以在发现自己能够按照构思勉强实现网页之后,我就把学习中心放到了服务器端上。不过每天还是会抽空写一写网页,避免手生。&/p&&br&&p&2)服务器端&/p&&p&最先了解的是HTTP协议,也就是浏览器和服务器之间是如何通信的。也就是当你在浏览器里键入网址按下回车直到网页显示在你浏览器的这个过程中,浏览器和浏览器之间发生了什么事情。这是很有意思的内容,我是以读小说的心情了解了这部分内容。了解这部分后,你就会明白类似为什么有时候会有404页面?在百度搜索框里键入的搜索词是如何提交到百度服务器的?为什么重新登录知乎的时候就不用再输入密码了?之类的问题了。&/p&&p&HTTP协议学习资料:&a href=&///?target=https%3A//www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&In Introduction to HTTP Basics&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&/people/& class=&internal&&@Vamei&/a&的博客:&a href=&///?target=http%3A///vamei/archive//2802811.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&协议森林&i class=&icon-external&&&/i&&/a&&/p&&br&&p&了解了HTTP协议之后,我就多少有些入迷了。看似神秘难懂的现象其实原理并不复杂,你反而会被吸引。接下来就进入到我投入时间最多的部分了——后端开发。记得当时了解Web开发的MVC(Model-View-Controller)模式后,有一种心血喷涌的感觉,觉得太有意思了(程序员别喷,我就是这么没见过世面)。我们以知乎为例子来说明MVC是个啥:&/p&&p&&a href=&///?target=https%3A///v2-0f9a88b7e281cc7ffd5e_b.png& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/v2-0f9a5&/span&&span class=&invisible&&8b7e281cc7ffd5e_b.png&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&p&每个人的主页都是相同的布局和风格,例如最上面的菜单搜索栏,颜色分割,左边显示动态等,右边是个人信息等,然后具体的内容却因人而异——每个人的头像,名字,动态都是不一样的。那么知乎是如何保证每一个人看到的都是自己的主页呢?&/p&&br&&p&你可以把这个相同的布局想象成一个模板,里面有一个个空格子,当你用你的账户登陆页面时,想象你的电脑里有无数个小人根据你的账号从知乎后台的数据库里取出你的头像,动态,认证信息等等内容,然后对应着模板上规定好的位置,把对应的内容填进去。这些小人的动作实在是太快了,以至于你觉得这是在瞬间完成的。&/p&&br&&p&上面所说的模板就是MVC中的V,是View的缩写,负责显示。这样做的好处在于,如果知乎有一天突然想改变一下个人主页的风格,那么只需要改变这一个模板,然后几千万注册用户的主页就相应的变化了,因为模板是公用的,是不是省了很多事情?(早期的Web开发可不是这样哟,你可能要一个个用户去改,非常麻烦。)&/p&&br&&p&而这些小人除了摆放内容,它们真正负责的是业务逻辑,我们把他们叫做Controller,也就是MVC中的C。例如当你登陆的时候,这些小人要检查你的用户名是不是准确的,如果准确,它们要去数据库里取出你请求的信息等,如果用户名错误,它们要拦截住你的登陆。它们的职责还有很多,无法一一列举。在实际中,这些小人做的事情其实就是Python(或者其它脚本语言)做的事情。&/p&&br&&p&最后,MVC中的Model其实就是传给View的数据,包括上面的头像,用户名,动态等因人而异的数据。这些数据在知乎服务器上是以数据库表格(table)的形式存在的,你可以把它们想象成很多不同的excel表格,不同的表格储存着不同的信息,有些记录着知乎用户的个人信息,有些记录着回答,有些记录着评论等等,而这些表格之间又彼此联系,当你在知乎的不同网页间跳转的时候,上面说的那些小人就根据你的要求,组合对应的表格取出对应的数据,然后把他们放到模板对应的空格里,发送给浏览器。然后浏览器根据你写的CSS,用不同的颜色,大小等等,将数据很漂亮的显示出来。&/p&&p&这样做的好处是什么呢?虽然你最终在浏览器里看到的是一个完整的页面,但是在后端逻辑上它们都是区分开的——模型(M),视图(V)和控制器(C)的区分就保证了较高的可维护性——我可以随时修改主页的显示并看到效果,同样我可以随时加入一些业务逻辑。&/p&&p&如果你的学习坚持到这里了,首先要恭喜你。其次你可能已经知道一些非常成熟的Python Web框架了,例如Django,Flask等等,并且你可能看到了很多小白教程教你直接使用,毕竟大部分人可能觉得没有必要重复造轮子。&/p&&p&本来为了省事,我也打算直接用框架。我是在设计数据库的时候,当时在看SQLAlchemy文档,觉得相对自己的项目SQLAlchemy太过复杂,所以我决定自己写自己的ORM(名词不懂没关系),这对于当时的我来说是一件难度非常大的事情。于是我投入了极大的精力每天都在看关于SQL和Python相关的教程和资料,&a href=&///?target=https%3A///subject/3112503/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python核心编程(第二版) &i class=&icon-external&&&/i&&/a&给了我很大的启发。在自己完成了ORM后,又写了URL处理函数,同样没有用任何现成的Web框架。&/p&&p&现在回头看,我认为这一段时间的造轮子是提升编程能力最快的时候。比如为了写ORM,就必须去花很多时间学习SQL,去了解Python里面的metaclass,而如果用一个现成的框架,我很有可能偷懒不去关注某些细节。而不出问题还好,一旦出问题,我就只能跪。另外,造轮子迫使我在开始的时候就构思整个框架,因为我必须尽可能的考虑到所有的情况,于是就会不断的强迫自己完善知识体系,和别人的代码作对比从而改进自己的,这个过程充满了无尽的挫败感,但是得来的成就和快乐也是无可比拟的。&/p&&p&SQL书籍:&a href=&///?target=https%3A///Sams-Teach-Yourself-MySQL-Days/dp/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Sams Teach Yourself MySQL in 21 Days&i class=&icon-external&&&/i&&/a&&/p&&p&Python:&a href=&///?target=https%3A///subject/3112503/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python核心编程(第二版)&i class=&icon-external&&&/i&&/a&&/p&&p&Github上的优质Python资源:&a href=&///?target=https%3A///CodementorIO/Python-Learning-Resources& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CodementorIO/Python-Learning-Resources&i class=&icon-external&&&/i&&/a&&/p&&p&过程中还牵涉到部署,我的网站是跑在Linux上的。关于部署网上有非常多的优质教程,一搜一大把。这里就不再赘述。这些是我学习大致路线,当然过程中充满着小的磕磕绊绊,虽然网站上线了,貌似运行还比较顺利,但是如果以一个程序员的标准来要求自己,自己依然非常菜鸟。不过我并没有以前那样惧怕技术了,就像你明白魔术的背后的原理后,会更多的思考原理本身。&/p&&h2&2. 自学编程需要注意的问题&/h2&&p&很多人都推荐小白第一门语言选Python,因为语法简单。这句话只说了一半,Python确实容易上手,对初学者的门槛很低。但我发现,&b&对于小白真正的门槛在于系统知识,这就和用什么语言完全没有任何关系了。&/b&例如很多人学完了Python的语法,觉得确实简单,但是转头去用Python标准库的时候,却发现自己连文档都看不懂。标准库提供了Python和其它系统功能的接口,最终实现了Python和系统之间的互动。读标准库需要系统知识,比如操作系统,数据库,进程和线程,socket编程,网络协议等等,这些对于编程小白来才构成很高的门槛,但是只有学会这些,才能真正发挥出Python的威力来。&/p&&p&这也是我觉得自己的经历对小白是有价值的一个原因。因为设计一个动态的网页是一个很不错的练手Project。建立网页(Web App)会逼迫你了解从你在浏览器里键入地址按下回车到网页显示在浏览器的过程中,浏览器,网络,服务器都干了些什么。具体到技术上面,你不得不去学习前端的HTML,CSS和JavaScript,后端的脚本,数据库,操作系统等。也就是说,这个过程能够促使你去主动学习上面提到的系统知识,如果你再做另外一个项目,你就不会像现在这样无从下手,而有能力去进行一些技术性的探讨,所以我认为这是一个非常好的练手项目。&/p&&p& 1)一定要空出时间补充理论知识&/p&&p&很多人会强调learn by doing,边做项目边学习,这也是我自己采用的方式。在这种方式中,你不断犯错,改正……学习效率非常高。但是,很多人走了极端,最后的结果就是不注意理论知识的学习。你会发现自己Google的能力越来越高,但是真实的编程能力并没有得到提升。如果有这种情况,你需要反思一下。&/p&&p&一种可能是你太过于依赖各种成熟的框架,结果编程就变成了用「胶水」去粘合不同的框架完成需求。就好比你的Web App用了SQLAlchemy,虽然自己不太懂SQL,但是网站跑的也还不错。这时候如果数据库出现了问题,那你就只能跪了。&/p&&p&另外一种可能是你完全沉浸在做项目中,忽略了学习理论知识。做项目虽然充满困难,但回报是强烈的成就感,很容易沉浸其中。我觉得这是极其错误的。首先半路出家的程序员都没有经过系统的学习,没有形成自己的知识体系,如果你不懂数据结构,算法复杂度,操作系统这些理论,那么你能达到的高度就极其有限。所以,在每天做项目的同时,一定要保证抽出一定的时间,恶补理论知识。这部分的书单在豆瓣和知乎上都有很多总结,可以自行搜索。&/p&&p&2)不要太纠结于无意义的问题,比如什么框架好,XX语言比XX语言好啦这种问题。前期确定了练手项目,就去专心积累代码量,积累基础知识。那些你现在还看不懂的炫酷技术你慢慢也就能明白是怎么回事了,反而没有基础,再炫酷的框架对你而言都是天书。&/p&&p&3)学会发问。好问题是建立在你自己已经实践或者思考的基础上问出来的,这是对自己的负责,也是对别人的尊重。不要一遇到困难就喜欢直接上网搜索:「这个问题是怎么回事啊?」,「我不明白你能不能帮我看看……」。&/p&&p&4)学好英语。&/p&&p&THE END&/p&&p&最后,给自己打个广告,如果学英语,一定要关注我。&/p&&br&&img src=&/v2-5b619dc58527acaf56c88b139a9790b8_b.png& data-rawwidth=&600& data-rawheight=&293& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-5b619dc58527acaf56c88b139a9790b8_r.png&&
我是真正零基础开始学Python的,从一开始的一窍不通,到3个月后成功搭建了一个动态网站(没有用任何框架)。相比于计算机大牛,我更加知道一个小白将会遇到什么坑,遇到哪些难点。我把我的学习过程写在下面,并附上在每个阶段的学习资料,希望对零基础的Pyt…
&img src=&/50/ea999ac239adbc4bbfa22c_b.png& data-rawwidth=&600& data-rawheight=&160& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/50/ea999ac239adbc4bbfa22c_r.png&&毕业/失业的状态持续了两个月了,七月份以来每天沉迷屁股不能自拔,感觉自己已经是个废人了。今天突然发现之前的一篇专栏居然有2元的赞赏,花了五分钟寻找余额的入口又花了一分钟把一块九毛八揣进自己裤兜里,欣然获得了一小时网费以后,终于决定克服拖延症再花一小时写一篇公众号开发的记录,也算对得起知友的赞赏。(然而磨磨蹭蹭写了四个多小时)&p&老规矩,事先声明,技术水平很菜,文章也只是对微信官方文档的一点简单测试和个人 参考结合别处文章(后面会列参考链接) 给出的一种简单实现,纯属娱乐。另外,微信公众号开发真的不是多难的事情,一来官方接口丰富文档详尽,二来开发者众多,网络上随处能获得大量的教程乃至代码资源。之所以写这几篇文章,主要还是作为自己的学习笔记,理解微信的消息机制和开发流程;而且网上的资源大多是 PHP 或 Java 的,相比 Python 而言学习成本更高一些,所以还是一边尽力整合不多的已有的 Python 教程,一边自己测试,记录下来供大家参考。&/p&&p&提要:&/p&&p&0、明需求,读文档,划重点;&/p&&p&1、微信公众帐号开发者测试帐号初步体验高级接口;&/p&&p&2、没有认证的个人订阅号如何实现回复图片、语音等消息类型;&/p&&p&3、一些可能的简单玩法,抛砖引玉。&/p&&br&&p&&b&0&/b&&/p&&p&这篇文章所需要的基础在前两篇都写到了,其实也没什么太专业的要求,主要参考第一篇把平台搭起来,通过了token认证就行。&/p&&br&&p&之前我们主要实现了:文字自动回复、接收用户的图片消息后调用微软 &a href=&/?target=http%3A//How-old.net& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&How-old.net&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a& 的人脸识别接口返回性别和年龄的结果、调用图灵机器人的 API 实现机器人聊天、接收用户的语音消息后通过提取微信自带的 Recognition 字段实现语音转文字并回复文字消息。‘’&/p&&p&可以发现,我们之前做的事情里,尽管分别处理了文字、图片、语音三种类型的消息,但是对用户的回复却都是文字消息。而在实际的应用中,我们可以在编辑模式和与关注者的私聊界面中是可以回复文字、图片、语音、视频和图文消息的(但是编辑模式和开发模式不能共存)。&/p&&br&&p&于是我们考虑如何在开发者模式下回复其他类型的文字消息。查看官方文档中关于被动回复的说明。&/p&&p&&a href=&/?target=http%3A//mp./wiki/1/cabc67e6c551.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&被动回复用户消息&i class=&icon-external&&&/i&&/a&&br&&/p&&p&划重点:&/p&&blockquote&现支持回复文本、图片、图文、语音、视频、音乐&br&&br&请注意,回复图片等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。&/blockquote&&p&好的我们知道了,我们是可以回复图片等类型的消息的,然而需要使用素材管理接口。继续读文档。&/p&&p&&a href=&/?target=http%3A//mp./wiki/13/8deb21f25ae8d.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&公众号类型的接口权限说明&i class=&icon-external&&&/i&&/a&&br&&/p&&p&划重点:未认证订阅号号是&s&他喵的&/s&没有素材管理的接口权限的。&/p&&p&好嘛,我就是&s&药丸&/s&要玩怎么办,微信给开发者提供了测试帐号,读文档。&/p&&p&&a href=&/?target=https%3A//mp./wiki%3Ft%3Dresource/res_main%26id%3Dmp%26token%3D%26lang%3Dzh_CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&接口测试号申请&i class=&icon-external&&&/i&&/a&&br&&/p&&p&到此准备工作结束。&/p&&br&&p&&b&1&/b&&/p&&p&好了,站着别动。啊不,准备战斗。&/p&&p&&a href=&/?target=http%3A//mp./debug/cgi-bin/sandbox%3Ft%3Dsandbox/login& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&微信公众平台&i class=&icon-external&&&/i&&/a& 微信扫码登陆。&br&&/p&&img src=&/50/3e3df8a0a01dccd6f562e2_b.png& data-rawwidth=&1097& data-rawheight=&478& class=&origin_image zh-lightbox-thumb& width=&1097& data-original=&/50/3e3df8a0a01dccd6f562e2_r.png&&&p&记下来 appID 和 appsecret ,后面要用来获取 access_token,下面的接口配置信息,可以按照我们在&a href=&/p/& class=&internal&&从零开始 Python 微信公众号开发 - 小段同学的杂记 - 知乎专栏&/a&中介绍的重新配一个,也可以直接把之前弄好现在用着的填过来,也是可以成功验证Token ,由此看出多个微信公众号其实是可以共用一个后台的。&/p&&br&&p&然后我们根据文档进行图片的上传和获取已有素材列表。&/p&&p&&a href=&/?target=http%3A//mp./wiki/10/10ea5a49290dfd43d006.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&新增永久素材&i class=&icon-external&&&/i&&/a&&br&&/p&&p&以上传图片为例(其他的类型我本着能偷懒就偷懒的原则,当作作业留给大家了)。上传图片需要 access_toke , type=image 和读取文件三个参数。&/p&&p&比较规范的写法为:&sup&1&/sup&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def get_media_ID(path):
img_url='https://api./cgi-bin/material/add_material'
payload_img={
'access_token':get_token(),
'type':'image'
data ={'media':open(path,'rb')}
r=requests.post(url=img_url,params=payload_img,files=data)
dict =r.json()
return dict['media_id']
&/code&&/pre&&/div&&p&其中 get_token()方法需要提供 appid 和 secret:&sup&1&/sup&&/p&&br&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def get_token():
payload_access_token={
'grant_type':'client_credential',
'appid':'xxxxxxxxxxxxx',
'secret':'xxxxxxxxxxxxx'
token_url='https://api./cgi-bin/token'
r=requests.get(token_url,params=payload_access_token)
dict_result= (r.json())
return dict_result['access_token']
&/code&&/pre&&/div&&p&当然你也可以写的比较随意,因为上传素材这件事不一定要放到服务器上去,甚至自己在本地也可以做。&br&&/p&&p&其中 access_token 可以直接在 &a href=&/?target=http%3A//mp./debug& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&微信公众平台接口调试工具&i class=&icon-external&&&/i&&/a& 中获得。&/p&&img src=&/50/5c050b82d96af69d6427bbe_b.png& data-rawwidth=&904& data-rawheight=&441& class=&origin_image zh-lightbox-thumb& width=&904& data-original=&/50/5c050b82d96af69d6427bbe_r.png&&&img src=&/50/f6c524dcd09f809b743d3e0e4f04d7cc_b.png& data-rawwidth=&900& data-rawheight=&425& class=&origin_image zh-lightbox-thumb& width=&900& data-original=&/50/f6c524dcd09f809b743d3e0e4f04d7cc_r.png&&&p&可以看到 access_token 有效期为两小时。(每天请求次数上限 2000 次)&br&&/p&&p&&img src=&/50/3f1e609ab14c473ce0c6c407a3c1c9ae_b.png& data-rawwidth=&1338& data-rawheight=&600& class=&origin_image zh-lightbox-thumb& width=&1338& data-original=&/50/3f1e609ab14c473ce0c6c407a3c1c9ae_r.png&&测试上传图片,可以看到返回了 media_id 和 url。&/p&&br&&p&&a href=&/?target=http%3A//mp./wiki/15/bc4cddbfe2e95b3.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&获取素材列表&i class=&icon-external&&&/i&&/a&&br&&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import requests
import json
url=&https://api./cgi-bin/material/batchget_material?access_token=yourtoken&
&type&:&image&,
&offset&:0,
&count&:20
data = json.dumps(datas)
a=requests.post(url=url,data =data)
print(a.text)
&/code&&/pre&&/div&&p&&img src=&/50/3d3ffcd43981bcd4a5eedc12_b.png& data-rawwidth=&1328& data-rawheight=&583& class=&origin_image zh-lightbox-thumb& width=&1328& data-original=&/50/3d3ffcd43981bcd4a5eedc12_r.png&&将返回的 json 数据包格式化以后:&/p&&p&&img src=&/50/df52e6de193b6f106a76b1d_b.png& data-rawwidth=&581& data-rawheight=&303& class=&origin_image zh-lightbox-thumb& width=&581& data-original=&/50/df52e6de193b6f106a76b1d_r.png&&可以看到列出了我们刚才上传的图片,给出了 media_id 和 url。&/p&&p&现在我们的素材库里已经有了图片素材,接下来考虑如何回复图片消息。&/p&&p&我们都应该知道,公众平台和用户的对话是用 XML 来交换信息的。也就是说,我们从用户那里接收到一个 XML 字串,解析后取得 FromUserName (用户ID,在回复消息时编程ToUserName)、MsgType 和相应的信息。同样的,我们在回复消息时也要把消息内容封装成XML 返回。&/p&&p&考虑我们之前已有的 templates/reply_text.xml :&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$def with (toUser,fromUser,createTime,content)
&ToUserName&&![CDATA[$toUser]]&&/ToUserName&
&FromUserName&&![CDATA[$fromUser]]&&/FromUserName&
&CreateTime&$createTime&/CreateTime&
&MsgType&&![CDATA[text]]&&/MsgType&
&Content&&![CDATA[$content]]&&/Content&
&/code&&/pre&&/div&&p&现在需要回复图片信息,在目录下新建 reply_image.xml ,并参考文本消息的结构,写出相应的内容。唯一的不同之处就在于,文本消息的 content 变成了图片素材的 media_id 。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$def with (toUser,fromUser,createTime,media_id)
&ToUserName&&![CDATA[$toUser]]&&/ToUserName&
&FromUserName&&![CDATA[$fromUser]]&&/FromUserName&
&CreateTime&$createTime&/CreateTime&
&MsgType&&![CDATA[image]]&&/MsgType&
&MediaId&&![CDATA[$media_id]]&&/MediaId&
&/code&&/pre&&/div&&p&现在我们有了图片素材,也有了回复图片消息的模版,直接修改 weixinInterface.py 添加相应的逻辑判断,回复图片消息即可。这里具体的代码就不贴了,因为牵扯了原来的一些逻辑,改的比较乱,所以最好还是自己新建一个后台,不要共用后台…其实也就相比回复文本也只用修改一行 return :&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&//return self.render.reply_text(fromUser,toUser,int(time.time()), msg)
return self.render.reply_image(fromUser,toUser,int(time.time()), media_id)
&/code&&/pre&&/div&&p&贴两张测试结果的图片。&/p&&img src=&/50/9a130e6e981efcebf1506c_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/9a130e6e981efcebf1506c_r.jpg&&&img src=&/50/6edbaa7ae2f719256afff_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/6edbaa7ae2f719256afff_r.jpg&&&p&(由于用的同一后台,也顺手测试了原来的个人号,无法提供服务)&br&&/p&&br&&br&&p&&b&2&/b&&/p&&p&上面的测试号测试通过了,但是依然没有解决我们的核心需求,就是让自己未认证的没有素材管理权限的服务号被动回复图片信息。起初我是想着能不能在公众平台后台的素材管理里找到media_id 的字段的,结果找来找去找不到,偏偏发送消息的 XML 模版里是把 media_id 作为素材的唯一标识的,也只能另寻他法。(如果有办法能获取未认证订阅号素材管理中素材列表的media_id,请务必告知)&/p&&p&解决办法其实是相对简单的,因为发送信息是双向的,你向用户发送信息需要提供 media_id,用户给公众号发的消息里自然也带上了 media_id ,这一点在接收普通消息的官方文档里是可以看到的,只不过我们在之前就算对图片和语音消息做了一定的处理,也没有用到这个字段而已。现在我们知道,只要拿到了 media_id ,就等于在微信的素材服务器里拿到了资源,自然也就可以用它来作为消息返回了。&/p&&p&当然,这么做也有明显的缺陷,因为理论上讲…用户发送的消息是作为临时图片存储的,所以有效期只有三天…那又有什么办法呢…&/p&&p&这里我们做一个简单的测试就好,还是像我们最初做文本消息时的鹦鹉学舌一样,用户发送图片公众号原样回复图片,用户发送语音,公众号原样回复语音。&/p&&p&首先添加
templates/reply_voice.xml &/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&$def with (toUser,fromUser,createTime,media_id)
&ToUserName&&![CDATA[$toUser]]&&/ToUserName&
&FromUserName&&![CDATA[$fromUser]]&&/FromUserName&
&CreateTime&$createTime&/CreateTime&
&MsgType&&![CDATA[voice]]&&/MsgType&
&MediaId&&![CDATA[$media_id]]&&/MediaId&
&/code&&/pre&&/div&&p&然后修改 weixinInterface.py ,当然写的比较简单,具体的代码可以自己参照前两篇完善。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&if msgType == 'image':
media_id = xml.find('MediaId').text
return self.render.reply_image(fromUser,toUser,int(time.time()), media_id)
elif msgType == 'voice':
media_id = xml.find('MediaId').text
return self.render.reply_voice(fromUser,toUser,int(time.time()), media_id)
&/code&&/pre&&/div&&p&测试图片:&/p&&img src=&/50/35061ac2bbbe43fbdda12_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/35061ac2bbbe43fbdda12_r.jpg&&&p&注:&br&&/p&&br&&p&①不同公众号间素材并不能串用,就好像我们刚才将图片上传到测试号以后拿到的 media_id 并不能用来在主号中回复;&/p&&br&&p&②不同公众号的用户发送的图片也不能串用,这个测试一下就知道了,记录下来用户发送图片的 media_id ,然后用另一个号请求这张图片。如图。&/p&&img src=&/50/d4f9e05e64ea_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/d4f9e05e64ea_r.jpg&&&img src=&/50/58f09bcdf5e2f0d083d76c_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/58f09bcdf5e2f0d083d76c_r.jpg&&&p&③微信发送图片其实是支持 gif 动图的,但是显示的时候全部都是静态的,个人测试安卓上如果点全图下载到本地以后,用本地的图片查看器是会动的。但是要注意微信的自定义表情并不属于图片,而是一种不支持的格式。&br&&/p&&p&④后续当然不要做这种原样返回的事情,可以自己多尝试一些点子,比如交换图片,交换语音什么的。今天一次性写太多太累了,懒得动脑子了。&br&&/p&&p&思考题(我也不会):&/p&&p&语音是不能转发只能收藏的。但是我们刚才却抓到了用户语音的 media_id 并回复回去,理论上讲是可以转发给任何一个人的。由此有没有可能找到转发语音消息的办法?&/p&&br&&p&&b&3&/b&&/p&&p&至此大体上实现了我们要研究的内容和要实现的需求。只是还要探究一下拿这个东西做什么。&/p&&p&抛砖引玉吧,简单提两点,现在也写的有点乏了。&/p&&br&&p&①斗图&/p&&p&前几天我一个朋友说他发现微软小冰的微信号能斗图了,发送表情的话能回复表情。当时我还挺惊讶的,因为微信公众号是不支持自定义表情的(QQ 表情和 emoji 可以作为文本处理,这个可以自行探究,也可以使用回复文本消息的办法回复 QQ 表情和 emoji ),如果接收到自定义表情的话微信后台显示的是 【收到不支持的消息类型,暂无法显示】。既然连接收都不支持,更何况回复呢。再说都识别不了对方究竟在发什么,又何来斗图一说呢。&/p&&p&实地探测后发现,微软小冰的回复全部都是图片格式,而且回复内容和发送的内容毫无关系。基本上认定在后台的识别中如果遇到【收到不支持的消息类型,暂无法显示】就任意回复一条静态的表情包图片,也可能会连续发送某一系列表情。如图。&/p&&img src=&/50/5bd6da575a4b2d5b8f72fa0c90a5f45b_b.jpg& data-rawwidth=&720& data-rawheight=&1280& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&/50/5bd6da575a4b2d5b8f72fa0c90a5f45b_r.jpg&&&p&这个自然也不难实现,只要自己积累一部分表情包的素材,然后添加判断【收到不支持的消息类型,暂无法显示】的逻辑后从 media_id 的列表中任意回复就好。这个感兴趣可以自己尝试。&/p&&p&②换图&br&&/p&&p&因为前面提到,未认证的个人订阅号要通过获取用户发送素材的 media_id 来回复图片消息,而用户图片的有效期只有三天,这样一来很难自己长期维护一个良好可用的素材库。既然如此不如干脆就让用户们互相伤害。想法来自于前段时间看到和菜头做的图友 App ,用户交换图片。你发一张蓝天白云,我发一张花花草草,十分和谐。借鉴这个想法的话,我们直接作为平台,交换用户发来的图片即可。当然这种想法远非原创,很多人曾经做过,比如我在找参考资料时就在知乎看到了这个回答 &a href=&/question//answer/& class=&internal&&微信公众号认证后高级接口如何玩耍? - 大强的回答&/a& 里面图片漂流的做法也就是我想表达的这个意思。&/p&&p&其他的就不再赘述了,好困。还是一口气熬夜写完,随后再完善吧。&/p&&br&&p&参考资料(并未验证是否是第一手原创,仅供参考,无利益相关):&/p&&p&1 &a href=&/?target=http%3A///weixin/901.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&利用python 实现微信公众号群发图片与文本消息功能&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&a href=&/?target=http%3A///wuhuacong/p/4443006.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&C#开发微信门户及应用(26)-公众号微信素材管理&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&/?target=http%3A///main/index-do-detail-id-1321& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&微信公众平台开发多的常见问题解惑&i class=&icon-external&&&/i&&/a&&br&&/p&&p&此外,Github 上有一些开发相对完善的项目,可以根据个人情况进行学习或使用:&/p&&p&&a href=&/?target=https%3A///search%3Futf8%3D%25E2%259C%Dpython%2Bweixin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Search · python weixin · GitHub&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&a href=&/?target=https%3A///search%3Futf8%3D%25E2%259C%Dpython%2Bwechat%26type%3DRepositories%26ref%3Dsearchresults& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Search · python wechat · GitHub&i class=&icon-external&&&/i&&/a&&br&&/p&&br&&p&写在最后:&/p&&p&这应该是这系列最后一篇了,因为未认证的个人订阅号做到这里基本也就到头了,作为一个学习者,了解到这个程度以后再在测试号上体验一下其余的高级接口也就差不多了。更多的内容要到有机会亲自参与认证订阅号或者服务号以后才能详细学习吧。而且这之后的门槛估计也不在某门语言或者微信官方的接口上面,而是更完善的 Web 开发能力和知识体系吧。&/p&&p&当然,应用级编程的门槛很大程度上是学习热情和学习能力。假如只谈入门、复制粘贴、做个测试(也就是我这种水平的),实在是没什么门槛的事情。我一直当作笔记来写,没想到还有许多人看,可能是我比较啰嗦,写出来的东西比较符合大家一贯的寻找答案的方式吧。当然,还望各位能借他山之石,做出更有意思的东西出来。&/p&&p&最后照例不贴二维码了反正也要被知乎转格式。&/p&&p&有兴趣的可以搜一下公众号,不怎么推文章,不怎么看后台,不怎么打理,取关的比新加关注的多:鱼香肉丝盖饭(id:rose-fun)(今天改来改去我都不知道后台最后长什么样子了,容我明天起床再顺一遍逻辑)&/p&&br&&p&完结撒花。&/p&&p&谢谢观众大老爷们。&/p&
毕业/失业的状态持续了两个月了,七月份以来每天沉迷屁股不能自拔,感觉自己已经是个废人了。今天突然发现之前的一篇专栏居然有2元的赞赏,花了五分钟寻找余额的入口又花了一分钟把一块九毛八揣进自己裤兜里,欣然获得了一小时网费以后,终于决定克服拖延症…
&img src=&/50/5bfb54f7deb02c7f288aa2d50e149b65_b.png& data-rawwidth=&1920& data-rawheight=&514& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/50/5bfb54f7deb02c7f288aa2d50e149b65_r.png&&前些日子在知乎上看到了一篇文章 &a href=&/p/& class=&internal&&Python公众号开发部分代码开源 - 学习编程 - 知乎专栏&/a& 。文章里倒是给出了一些可以用的源码,可惜没具体说怎么部署到自己的服务器和公众号,也没有对源码进行应有的解释,自己摸索了几天以后算是成功搭好了一个简单的 python 微信公众号后台,对刚开始的源码进行了一些改善,正好专栏也很久没更新了,写一篇记录一下过程吧。&br&&p&主要工具:SAE+微信公众号+Git+Python本地环境(最好已经安装好了Git并配置好了Python IDE,比如Pycharm)&/p&&h2&1. 工欲善其事&/h2&&p&首先要简单介绍一下一些准备工作。&/p&&p&1.1 微信公众号&/p&&p&第一步是要注册一个个人微信公众号(个人账号不支持认证),按照&a href=&/?target=https%3A//mp./& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&mp./&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a& 给出的过程依次填写需要的信息就可以完成申请,如果已有账号的话可以直接登录。&/p&&p&登录以后可以看到左边栏中的自动回复功能:&br&&/p&&img data-rawheight=&248& data-rawwidth=&215& src=&/1e36e7e18df9d9f4a23d250a42872e07_b.png& class=&content_image& width=&215&&&p&在一般的使用中,我们可以通过设置关键字实现一些基本的自动回复功能,但是这样的关键字回复远远不能满足我们的实际需求,比如我们要实现一个查快递的功能,必然是要通过调用快递接口对不同用户的不同输入给出不同的输出结果,在这样的情况下关键字回复就显得很鸡肋了。于是我们选择了开发者模式。&/p&&p&&img data-rawheight=&201& data-rawwidth=&208& src=&/8bed1ba6987_b.png& class=&content_image& width=&208&&在基本配置中,我们只需要修改URL、Token和EncodingAESKey三项配置即可,由于我们现在还没有配好自己的服务器,微信公众号这边的设置到这里暂停,等我们有了服务器获取了地址以后回来填写就可以了。&/p&&p&1.2 SAE&/p&&p&这次我们使用新浪云作为我们的服务器,注册登录&a class=& external& href=&/?target=https%3A//& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a& ,新用户会有一定的优惠云豆,老用户充个十块也足够我们完成很多学习任务了。&/p&&p&选择云应用,进入控制台后创建新应用。&/p&&p&&img data-rawheight=&431& data-rawwidth=&1168& src=&/bb8d431dcdbc60d8f2e52ce_b.png& class=&origin_image zh-lightbox-thumb& width=&1168& data-original=&/bb8d431dcdbc60d8f2e52ce_r.png&&输入二级域名和应用名称(必填项),在下面的运行环境中选择 Python2.7 - 空应用。&/p&&p&&img data-rawheight=&332& data-rawwidth=&531& src=&/0fb7c2c727dbb02dbd5db96_b.png& class=&origin_image zh-lightbox-thumb& width=&531& data-original=&/0fb7c2c727dbb02dbd5db96_r.png&&成功创建应用后,会获得相应的一些配置数据和密钥,当然这些内容这次用不到,主要用到的就是登陆账号和安全密码。&/p&&img data-rawheight=&328& data-rawwidth=&834& src=&/cf532f65f65e5aac25afd111d81a2571_b.png& class=&origin_image zh-lightbox-thumb& width=&834& data-original=&/cf532f65f65e5aac25afd111d81a2571_r.png&&&p&SAE平台的代码版本控制分为Git和SVN,两者可以自由选择,这次我们选择使用Git进行代码的上传操作。&/p&&img data-rawheight=&532& data-rawwidth=&733& src=&/4eb5bdb84f0d6a4c69e27af_b.png& class=&origin_image zh-lightbox-thumb& width=&733& data-original=&/4eb5bdb84f0d6a4c69e27af_r.png&&&p&1.3 Git&/p&&p&对于Windows系统,电脑上如果安装了 Github Desktop 的话,应该就自带了 Git Bash 和 Git Shell 这样的工具,如果之前没有安装过 Git 相关的软件,可以自行搜索 Git 以后安装 Git for Windows。&/p&&p&Git 刚接触时可能很复杂,用起来功能很强大但繁琐,初学者可能绕来绕去就绕晕了,但是在这次的搭建过程中我们其实只需要用到四五条极为简单的命令即可,所以完全无需担心 Git ,也不要让 Git 成为你拒绝迈出第一步的障碍。(关于 SAE 的代码管理,详见&a class=& external& href=&/?target=https%3A///doc/sae/tutorial/code-deploy.html%23git& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&/doc/sae/t&/span&&span class=&invisible&&utorial/code-deploy.html#git&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&)&/p&&p&下面就让我们进入到真正的开发阶段吧!&/p&&h2&2. 捅破窗户纸&/h2&&p&犹记得我大一的时候公众号刚刚兴起,当时我还兴致冲冲地注册了账号,设置了一大堆的关键字自动回复,坚持了数天的图文消息推送,但是当我真正开始研究开发者模式,真正想去调用一些接口时却发现,好像自己该学的也都学了,该用的也都用过,就是串不到一起去,做不出想要的东西来(当时用的好像还是 PHP

我要回帖

更多关于 无法加载模块 webchat 的文章

 

随机推荐