├── .gitignore
├── .project
├── .pydevproject
├── README.md
├── __init__.py
├── app
├── __init__.py
├── common
│ ├── __init__.py
│ └── function.py
├── config
│ ├── __init__.py
│ └── config.py
├── db
│ ├── DBmain.py
│ └── __init__.py
├── douyu
│ ├── __init__.py
│ ├── html_downloader.py
│ ├── html_parser.py
│ ├── liveDataByRoomId.py
│ ├── liveDb.py
│ ├── main.py
│ └── url_manager.py
└── server
│ ├── TextMsgHandle.py
│ ├── __init__.py
│ ├── douyuServer.py
│ ├── main.py
│ ├── subscribe.py
│ └── userDb.py
├── doc
├── index.rst
├── show.png
├── spider.sql
├── sub.png
├── top.jpg
└── word.png
├── main.py
└── send.py
/.gitignore:
--------------------------------------------------------------------------------
1 | wxpy.pkl
2 | wxpy_puid.pkl
3 | friend.txt
4 | app/__pycache__
5 | app/*/__pycache__
6 | autoSend
7 | send_*
8 | venv
9 | .idea
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | wxPython
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.python.pydev.pythonNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 | Default
4 | python 2.7
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 使用wxpy爬取需求信息发送微信
2 |
3 | ## 技术栈:
4 |
5 | python3.6 + pip3 + wxpy + wechat_sender + urllib + bs4 +pymysql
6 |
7 | ## 下载 (运行`python3.6 `)
8 | ##### 如果安装报错,请用pip安装指定模块,对于的wxpy的学习,请github自行搜索
9 |
10 | git clone https://github.com/Topthinking/wxPython.git
11 |
12 | cd wxPython
13 |
14 | python main.py
15 |
16 | ## 2017年6月25日
17 | ```
18 | 初次提交,本地数据进行斗鱼主播的直播情况查询
19 | ```
20 | ## 2017年6月27日
21 | ```
22 | 1.使用pymysql来动态捕获查询数据
23 | 2.同时扩展了库与库之间的关系,待优化...
24 | ```
25 | ## 2017年6月28日
26 | ```
27 | 1.数据的增删改查
28 | 2.回复格式为 dy:[名称]:[房间号]:[别名] 即可完成添加或者修改,
29 | 例如回复: dy:yyf:58428:rua ,
30 | 结果就是更新rua别名,那么就可以回复rua获取房间号58428的直播情况
31 | 可以回复多个别名,他们以英文的逗号隔开,比如 dy:yyf:58428:rua,胖头鱼
32 | 3.优化sql语句对数据库的直接操作,防止sql注入
33 | 4.同时处理了输入格式错误返回的信息
34 | ```
35 | ## 2017年6月30日
36 | ```
37 | 1.加入订阅功能,具体回复:"我的订阅" 查看详情
38 | 2.放出数据库表结构,在doc目录下
39 | ```
40 | ## 说明
41 |
42 | > 本项目主要学习Python爬虫,配合微信发送爬取信息,使得学习不会那么枯燥
43 |
44 | > 如果觉得不错的话,您可以点右上角 "Star" 支持一下 谢谢! ^_^
45 |
46 | > 如有问题请直接在 Issues 中提,或者您发现问题并有非常好的解决方案,欢迎 PR 👍
47 |
48 | ### 扫描二维码,验证信息输入'top'
49 | #### 工作时间可用(10:00 - 19:00)
50 | 
51 |
52 | # 效果截图
53 |
54 |
55 |
56 | # 词汇截图
57 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/__init__.py
--------------------------------------------------------------------------------
/app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/__init__.py
--------------------------------------------------------------------------------
/app/common/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/common/__init__.py
--------------------------------------------------------------------------------
/app/common/function.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | class CommonFn(object):
3 | def __init__(self):
4 | pass
5 |
6 | # 打印对象所有集合
7 | @staticmethod
8 | def prn_obj(obj):
9 | print('\n'.join(['%s:%s' % item for item in obj.__dict__.items()]))
10 |
--------------------------------------------------------------------------------
/app/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/config/__init__.py
--------------------------------------------------------------------------------
/app/config/config.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import pymysql
3 |
4 |
5 | class Config(object):
6 |
7 | @staticmethod
8 | def database():
9 | return dict(
10 | host="127.0.0.1",
11 | port=3306,
12 | user="root",
13 | passwd="root",
14 | db="spider",
15 | charset="utf8",
16 | cursorclass=pymysql.cursors.DictCursor
17 | )
18 |
--------------------------------------------------------------------------------
/app/db/DBmain.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import pymysql
3 | from app.config import config
4 |
5 |
6 | class DBModel(object):
7 | def __init__(self):
8 | self.conf = config.Config()
9 |
10 | def _connect(self):
11 | self.conn = pymysql.connect(**self.conf.database());
12 |
13 | def exeAllMySQL(self, sql, data=None):
14 | self._connect()
15 | try:
16 | with self.conn.cursor() as cursor:
17 | # 执行sql语句,进行查询
18 | if data is None:
19 | cursor.execute(sql)
20 | else:
21 | cursor.execute(sql, data)
22 | # 获取查询结果
23 | result = cursor.fetchall()
24 | # 没有设置默认自动提交,需要主动提交,以保存所执行的语句
25 | self.conn.commit()
26 | finally:
27 | self.conn.close()
28 |
29 | return result
30 |
31 | def exeOneMySQL(self, sql, data=None):
32 | self._connect()
33 | try:
34 | with self.conn.cursor() as cursor:
35 | # 执行sql语句,进行查询
36 | if data is None:
37 | cursor.execute(sql)
38 | else:
39 | cursor.execute(sql, data)
40 | # 获取查询结果
41 | result = cursor.fetchone()
42 | # 没有设置默认自动提交,需要主动提交,以保存所执行的语句
43 | self.conn.commit()
44 | finally:
45 | self.conn.close()
46 |
47 | return result
48 |
49 | def insertMySQL(self, sql, data):
50 | self._connect()
51 | try:
52 | with self.conn.cursor() as cursor:
53 | # 执行sql语句,进行查询
54 | cursor.execute(sql, (data))
55 |
56 | # 没有设置默认自动提交,需要主动提交,以保存所执行的语句
57 | self.conn.commit()
58 | finally:
59 | self.conn.close()
60 |
61 | def updateMySQL(self, sql, data):
62 | self._connect()
63 | try:
64 | with self.conn.cursor() as cursor:
65 | # 执行sql语句,进行查询
66 | cursor.execute(sql, (data))
67 |
68 | # 没有设置默认自动提交,需要主动提交,以保存所执行的语句
69 | self.conn.commit()
70 | finally:
71 | self.conn.close()
72 |
73 | def insertMySQLById(self, sql, data):
74 | self._connect()
75 | try:
76 | with self.conn.cursor() as cursor:
77 | # 执行sql语句,进行查询
78 | cursor.execute(sql, data)
79 | sql = " SELECT LAST_INSERT_ID() as id "
80 | cursor.execute(sql)
81 | result = cursor.fetchone()
82 | # 没有设置默认自动提交,需要主动提交,以保存所执行的语句
83 | self.conn.commit()
84 | finally:
85 | self.conn.close()
86 | return result
87 |
--------------------------------------------------------------------------------
/app/db/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/db/__init__.py
--------------------------------------------------------------------------------
/app/douyu/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/douyu/__init__.py
--------------------------------------------------------------------------------
/app/douyu/html_downloader.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import urllib.request
3 |
4 |
5 | class HtmlDownloader(object):
6 |
7 | @staticmethod
8 | def download(url):
9 | print(url)
10 |
11 | if url is None:
12 | return None
13 |
14 | headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
15 |
16 | req = urllib.request.Request(url=url, headers=headers)
17 |
18 | response = urllib.request.urlopen(req)
19 |
20 | if response.getcode() != 200:
21 | return None
22 |
23 | return response.read().decode()
24 |
--------------------------------------------------------------------------------
/app/douyu/html_parser.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from bs4 import BeautifulSoup
3 | import json
4 |
5 |
6 | class HtmlParser(object):
7 | def __init__(self):
8 | self.liveRoom = []
9 | self.attentionRoom = []
10 |
11 | def _get_live_room(self, soup):
12 |
13 | lists = soup.find_all("li")
14 |
15 | if lists is None or len(lists) == 0:
16 | return
17 |
18 | cur_rooms = []
19 |
20 | for _list in lists:
21 | rInfo = _list.find("a")
22 | if "data-rid" not in rInfo.attrs:
23 | continue
24 | rid = rInfo.attrs["data-rid"]
25 | rName = rInfo.attrs["title"]
26 |
27 | uNameInfo = rInfo.find("span", class_="dy-name")
28 | if uNameInfo is None:
29 | rUace = '-未识别-'
30 | else:
31 | rUace = uNameInfo.get_text()
32 |
33 | rNumber = rInfo.find("span", class_="dy-num")
34 | if rNumber is None:
35 | rNum = 0
36 | else:
37 | rNum = rNumber.get_text()
38 |
39 | tmpRoom = {
40 | "roomId": rid,
41 | "roomName": rName,
42 | "nickName": rUace,
43 | "roomNum": rNum
44 | }
45 |
46 | self.liveRoom.append(tmpRoom)
47 |
48 | cur_rooms.append(tmpRoom)
49 |
50 | return cur_rooms
51 |
52 | def getLiveRoom(self):
53 | return self.liveRoom
54 |
55 | def clearAttentionRoom(self):
56 | self.attentionRoom = []
57 |
58 | def getAttentionRoom(self):
59 | return self.attentionRoom
60 |
61 | def parse(self, html_cont):
62 |
63 | soup = BeautifulSoup(html_cont, 'html.parser', from_encoding="utf-8")
64 |
65 | return self._get_live_room(soup)
66 |
67 | def jsonParse(self, content):
68 |
69 | roomsData = json.loads(content["$ROOM.showData"])
70 |
71 | print(roomsData["child_cate"]["url"])
72 |
73 | return
74 |
75 | # 已开播
76 | if roomInfo["show_status"] == 1:
77 | self.attentionRoom.append({
78 | "roomId": str(roomInfo['room_id']),
79 | "roomName": roomInfo['room_name'],
80 | "nickName": roomInfo['owner_name'],
81 | "roomNum": roomInfo['levelInfo']['upgrade_exp']
82 | })
83 |
84 | @staticmethod
85 | def liveDataByRoomIdParse(content):
86 |
87 | roomInfo = json.loads(content["$ROOM"])
88 |
89 | roomshowData = json.loads(content["$ROOM.showData"])
90 |
91 | if "child_cate" not in roomshowData:
92 | search_url = roomshowData["game"]["url"]
93 | else:
94 | search_url = roomshowData["child_cate"]["url"]
95 |
96 | return {
97 | "roomId": str(roomInfo['room_id']),
98 | "roomName": roomInfo['room_name'],
99 | "nickName": roomInfo['owner_name'],
100 | "show_status": roomInfo["show_status"],
101 | "search_url": search_url
102 | }
103 |
--------------------------------------------------------------------------------
/app/douyu/liveDataByRoomId.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | # 根据roomID获取直播详情
3 |
4 | import json
5 |
6 | from future.types.newbytes import unicode
7 |
8 | from app.douyu import url_manager, html_downloader, html_parser
9 |
10 |
11 | class LiveDataByRoomId(object):
12 | def __init__(self):
13 | self.urls = url_manager.UrlManager()
14 | self.downloader = html_downloader.HtmlDownloader()
15 | self.parser = html_parser.HtmlParser()
16 |
17 | # 根据roomID号获取基本参数
18 | def attention(self, roomId):
19 |
20 | result = ''
21 |
22 | try:
23 | url = "http://www.douyu.com/ztCache/WebM/room/" + str(roomId)
24 |
25 | html_cont = self.downloader.download(url)
26 |
27 | content = json.loads(html_cont)
28 |
29 | if not content:
30 | result = None
31 |
32 | data = self.parser.liveDataByRoomIdParse(content)
33 |
34 | # 正在直播,需要获取直播人气值
35 | if data["show_status"] == 1:
36 | liveData = self.crawAttention(roomId, data["search_url"])
37 | data["roomNum"] = liveData["roomNum"]
38 | else:
39 | data["roomNum"] = 0
40 |
41 | result = data
42 |
43 | except Exception as e:
44 | print('craw failed:%s' % (e))
45 |
46 | return result
47 |
48 | # 根据分类的url获取具体的人气值
49 |
50 | def crawAttention(self, roomId, child_cate_url):
51 |
52 | findNumber = True
53 | count = 1
54 |
55 | result = ''
56 |
57 | while findNumber:
58 | try:
59 | url = "https://www.douyu.com" + str(child_cate_url) + "?page=" + str(count) + "&isAjax=1"
60 |
61 | html_cont = self.downloader.download(url)
62 |
63 | roomData = self.parser.parse(html_cont)
64 |
65 | for roomD in roomData:
66 | if roomD["roomId"] == str(roomId):
67 | findNumber = False
68 | result = roomD
69 |
70 | count = count + 1
71 |
72 | except Exception as e:
73 | print('craw failed:%s' % e)
74 |
75 | return result
76 |
77 | # 根据roomId判定房间是否存在
78 |
79 | def isExistRoom(self, roomId):
80 | url = "http://www.douyu.com/ztCache/WebM/room/" + str(roomId)
81 |
82 | html_cont = self.downloader.download(url)
83 |
84 | if unicode(html_cont, "utf-8") == '':
85 | return False
86 |
87 | content = json.loads(html_cont)
88 |
89 | if not content:
90 | result = False
91 |
92 | roomInfo = json.loads(content["$ROOM"])
93 |
94 | if not roomInfo['room_name']:
95 | return False
96 | else:
97 | return True
98 |
--------------------------------------------------------------------------------
/app/douyu/liveDb.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from app.db import DBmain
3 |
4 |
5 | class LiveDb(object):
6 |
7 | def __init__(self):
8 | self.db = DBmain.DBModel()
9 |
10 | def searchLiveState(self, param):
11 | sql = " SELECT * FROM dyLiveRoom WHERE alias LIKE %s "
12 | return self.db.exeAllMySQL(sql, param)
13 |
14 | def addLiveState(self, param):
15 | sql = "INSERT INTO dyLiveRoom (name,roomID,alias) values(%s,%s,%s)"
16 | return self.db.insertMySQL(sql, param)
17 |
18 | def isExistLive(self, param):
19 | sql = " SELECT * FROM dyLiveRoom WHERE roomId = %s ";
20 | return self.db.exeOneMySQL(sql, param)
21 |
22 | def updateLiveInfo(self, param):
23 | sql = " UPDATE dyLiveRoom set name=%s,alias=%s WHERE roomId = %s "
24 | return self.db.updateMySQL(sql, param)
25 |
--------------------------------------------------------------------------------
/app/douyu/main.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import threading
3 |
4 | from wechat_sender import Sender
5 |
6 | from app.douyu import url_manager, html_downloader, html_parser
7 | import json
8 | from future.backports.misc import count
9 |
10 |
11 | class SpilerLiveMain(object):
12 | def __init__(self):
13 | self.urls = url_manager.UrlManager()
14 | self.downloader = html_downloader.HtmlDownloader()
15 | self.parser = html_parser.HtmlParser()
16 | pass
17 |
18 | def craw(self, page=10):
19 | count = 1
20 |
21 | while count < page:
22 | try:
23 | url = "https://www.douyu.com/directory/all?page=" + str(count) + "&isAjax=1"
24 |
25 | html_cont = self.downloader.download(url)
26 |
27 | self.parser.parse(html_cont)
28 |
29 | count = count + 1
30 |
31 | except Exception as e:
32 | print('craw failed:%s' % (e))
33 |
34 | return self.parser.getLiveRoom()
35 |
36 | def attention(self, rooms=[]):
37 | if len(rooms) == 0:
38 | return
39 |
40 | for room in rooms:
41 | try:
42 | url = "http://www.douyu.com/ztCache/WebM/room/" + str(room)
43 |
44 | html_cont = self.downloader.download(url)
45 |
46 | content = json.loads(html_cont)
47 |
48 | if not content:
49 | continue
50 |
51 | self.parser.jsonParse(content)
52 |
53 | except Exception as e:
54 | print('craw failed:%s' % (e))
55 |
56 | return self.parser.getAttentionRoom()
57 |
58 | def crawAttention(self, rooms=[]):
59 |
60 | if len(rooms) == 0:
61 | return
62 | count = 1
63 | new_rooms = []
64 |
65 | while len(rooms):
66 | try:
67 | url = "https://www.douyu.com/directory/all?page=" + str(count) + "&isAjax=1"
68 |
69 | html_cont = self.downloader.download(url)
70 |
71 | roomData = self.parser.parse(html_cont)
72 |
73 | for roomD in roomData:
74 | if roomD["roomId"] in rooms:
75 | rooms.remove(roomD["roomId"])
76 | new_rooms.append(roomD)
77 |
78 | count = count + 1
79 |
80 | except Exception as e:
81 | print('craw failed:%s' % e)
82 |
83 | return new_rooms
84 |
85 | def clearAttention(self):
86 | self.parser.clearAttentionRoom()
87 |
--------------------------------------------------------------------------------
/app/douyu/url_manager.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | class UrlManager(object):
4 | def __init__(self):
5 | self.url = ''
6 |
7 | def has_new_url(self):
8 | return self.url != ''
9 |
10 | def get_new_url(self):
11 | if self.url == '':
12 | return None
13 |
14 | return self.url
15 |
16 | def add_new_url(self, url):
17 | self.url = url
18 |
--------------------------------------------------------------------------------
/app/server/TextMsgHandle.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | # 消息处理,文本消息
3 | from app.common import function
4 | from app.server import userDb, subscribe
5 |
6 | import sys
7 |
8 |
9 | class TextMsg(object):
10 | def __init__(self):
11 | self.common = function.CommonFn()
12 | self.userdbSer = userDb.User()
13 | pass
14 |
15 | def start(self, msg):
16 | # 判断用户的订阅的哪些信息
17 | # self.common.prn_obj(msg)
18 |
19 | msg.chat.send('已接收数据,正在处理中...')
20 |
21 | param = (msg.raw["FromUserName"],)
22 | data = self.userdbSer.getUserInfoByUserName(param)
23 |
24 | userId = data["id"]
25 |
26 | if msg.text == "我的订阅":
27 |
28 | self._mySubList(userId, msg)
29 |
30 | else:
31 | # 判定是否是请求订阅,格式:订阅:[斗鱼直播]
32 | sub = msg.text.split(":")
33 |
34 | if len(sub) == 2:
35 | if sub[0] == "订阅":
36 | # 订阅功能
37 | self._addSub(sub, userId, msg)
38 | elif sub[0] == "取消订阅":
39 | # 取消订阅功能
40 | self._cancelSub(sub, userId, msg)
41 | else:
42 | # 信息请求
43 | # 获取订阅信息
44 | param = (data["id"],)
45 | subData = self.userdbSer.getUserSubInfo(param)
46 |
47 | if len(subData) == 0:
48 | info = self._replay_subInfo()
49 | msg.chat.send("您需要订阅\n" + info)
50 | else:
51 | # 前往订阅类,处理订阅对应的信息请求
52 | subscribe.SubscribeHandle(subData, msg)
53 |
54 | def _addSub(self, sub, userId, msg):
55 | subName = sub[1]
56 | param = (subName, subName)
57 | subInfo = self.userdbSer.getSubInfo(param)
58 | if subInfo is None:
59 | info = self._replay_subInfo()
60 | msg.chat.send("订阅名称:【" + subName + "】系统还未提供\n" + info);
61 | else:
62 | # 判定有没有订阅该项目
63 | param = (userId, subInfo["id"])
64 | isSub = self.userdbSer.isSubUserInfo(param)
65 |
66 | if isSub is None:
67 | # 添加订阅
68 | # uid,subsribe_id,status
69 | param = (userId, subInfo["id"], 1)
70 | self.userdbSer.InsertUserSubInfo(param)
71 | msg.chat.send("订阅:【" + subInfo["name"] + "】成功,可以使用其功能")
72 | else:
73 | # 更新添加
74 | if str(isSub["status"]) == "1":
75 | msg.chat.send("您已经订阅:【" + subInfo["name"] + "】")
76 | else:
77 | param = (1, userId, subInfo["id"])
78 | self.userdbSer.updateUserSubInfo(param)
79 | msg.chat.send("订阅:【" + subInfo["name"] + "】成功,可以使用其功能")
80 |
81 | def _cancelSub(self, sub, userId, msg):
82 | subName = sub[1]
83 | param = (subName, subName)
84 | subInfo = self.userdbSer.getSubInfo(param)
85 | if subInfo is None:
86 | info = self._replay_subInfo()
87 | msg.chat.send("订阅名称:【" + subName + "】系统还未提供\n" + info);
88 | else:
89 | # 判定有没有订阅该项目
90 | param = (userId, subInfo["id"])
91 | isSub = self.userdbSer.isSubUserInfo(param)
92 |
93 | if isSub is None:
94 | info = self._replay_subInfo()
95 | msg.chat.send("您还未订阅:【" + subInfo["name"] + "】\n" + info)
96 | else:
97 | # 取消订阅
98 | # uid,subsribe_id,status
99 | param = (0, userId, subInfo["id"])
100 | self.userdbSer.updateUserSubInfo(param)
101 | msg.chat.send("取消订阅:【" + subInfo["name"] + "】成功")
102 |
103 | def _mySubList(self, userId, msg):
104 | param = (userId,)
105 | subData = self.userdbSer.getUserSubInfo(param)
106 |
107 | if len(subData) == 0:
108 | info = self._replay_subInfo()
109 | msg.chat.send("您还未进行订阅\n" + info)
110 | else:
111 | # 列出我的订阅
112 | info = '[咖啡]我的订阅列表:\n'
113 | count = 1
114 | for sub in subData:
115 | info = info + str(count) + "、订阅号:" + str(sub["id"]) + ";订阅名:" + str(sub["name"]) + "\n"
116 | count = count + 1
117 |
118 | sysInfo = self._replay_subInfo()
119 |
120 | msg.chat.send(info + sysInfo)
121 | pass
122 |
123 | def _replay_subInfo(self):
124 | # 获取目前可以订阅的功能
125 | subs = self.userdbSer.getSubList()
126 |
127 | info = '[拳头]当前系统可用订阅类型:\n'
128 | count = 1
129 | for sub in subs:
130 | info = info + str(count) + "、订阅号:" + str(sub["id"]) + ";订阅名:" + str(sub["name"]) + "\n"
131 | count = count + 1
132 |
133 | info = info + "\n您可以回复: 订阅:[订阅号,订阅名] \n[玫瑰]例如: 订阅:" + str(subs[0]["name"])
134 | info = info + "\n[嘘]把订阅改为取消订阅,其余不变,即可完成取消 "
135 | info = info + "\n回复:我的订阅 即可查询当前订阅内容\n[爱心]谢谢使用[爱心]"
136 | return info
137 |
--------------------------------------------------------------------------------
/app/server/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/app/server/__init__.py
--------------------------------------------------------------------------------
/app/server/douyuServer.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | # 处理斗鱼的数据接口
3 | from app.douyu import liveDataByRoomId, liveDb
4 |
5 |
6 | class DouyuServer(object):
7 |
8 | def __init__(self, msg):
9 | # 连接数据库
10 | self.douyuLiveDb = liveDb.LiveDb()
11 | self.liveSer = liveDataByRoomId.LiveDataByRoomId()
12 | self.msg = msg
13 |
14 | def liveDataByRoomId(self):
15 |
16 | newMsg = self.msg.text.split(":")
17 |
18 | sendMsg = self.msg.chat
19 |
20 | # 查询
21 | if len(newMsg) == 0 or newMsg[0] != "dy":
22 |
23 | param = ("%" + self.msg.text + "%",)
24 |
25 | lists = self.douyuLiveDb.searchLiveState(param)
26 |
27 | if len(lists) == 0:
28 | sendMsg.send(
29 | "您的查询超过系统爬取的范围\n可以回复格式为\n dy:[名称]:[房间号]:[别名1,别名2,别名3]\n即可完成添加或者修改,目前针对斗鱼直播数据\n例如: "
30 | "dy:yyf:58428:rua,胖头鱼")
31 |
32 | searchLive = False
33 |
34 | for _list in lists:
35 | liveData = self.liveSer.attention(_list["roomId"])
36 |
37 | self.msg.chat.send(self._livereplayInfo(liveData))
38 |
39 | searchLive = True
40 |
41 | if searchLive:
42 | sendMsg.send("数据发送完毕!")
43 | # 插入
44 | elif len(newMsg) != 0 and newMsg[0] == "dy":
45 |
46 | if len(newMsg) != 4:
47 | sendMsg.send("错误格式的数据")
48 |
49 | # name,roomId,alias
50 | # dy:top:12345:a,b,v,d
51 | # newMsg[1],newMsg[2],newMsg[3]
52 |
53 | # 先判断房间号在斗鱼是否存在
54 | if not self.liveSer.isExistRoom(newMsg[2]):
55 | sendMsg.send("房间号:【" + newMsg[2] + "】在斗鱼不存在,无法添加")
56 |
57 | param = (newMsg[2],)
58 |
59 | data = self.douyuLiveDb.isExistLive(param)
60 |
61 | if data is None:
62 |
63 | # 添加数据
64 | param = (newMsg[1], newMsg[2], newMsg[3])
65 |
66 | self.douyuLiveDb.addLiveState(param)
67 |
68 | sendMsg.send("数据添加成功")
69 |
70 | else:
71 |
72 | # 更新数据
73 | alias = data["alias"].split(",")
74 |
75 | newAlias = newMsg[3].split(",")
76 |
77 | for newAlia in newAlias:
78 | if newAlia not in alias:
79 | alias.append(newAlia)
80 |
81 | alias = ",".join(alias)
82 |
83 | # 更新房间信息
84 | param = (newMsg[1], alias, newMsg[2])
85 |
86 | self.douyuLiveDb.updateLiveInfo(param)
87 |
88 | sendMsg.send("房间号:【" + newMsg[2] + "】数据更新成功!")
89 |
90 | @staticmethod
91 | def _livereplayInfo(liveData):
92 |
93 | # 正在直播
94 | if liveData['show_status'] == 1:
95 | info = "房间名称:【" + liveData['roomName'] + "】已开播" \
96 | "\n房间号:" + liveData['roomId'] + \
97 | "\n主播昵称:" + liveData['nickName'] + \
98 | "\n人气值:" + liveData['roomNum'] + \
99 | "\n访问:https://www.douyu.com/" + liveData['roomId'] + "/"
100 |
101 | else:
102 | info = "房间名称:【" + liveData['roomName'] + "】未开播" \
103 | "\n房间号:" + liveData['roomId'] + \
104 | "\n主播昵称:" + liveData['nickName'] + \
105 | "\n访问:https://www.douyu.com/" + liveData['roomId'] + "/"
106 |
107 | return info
108 |
--------------------------------------------------------------------------------
/app/server/main.py:
--------------------------------------------------------------------------------
1 | """
2 | 初始化机器人,以及响应好友消息请求
3 | """
4 | # coding:utf-8
5 | import datetime
6 | import time
7 |
8 | from wechat_sender.listener import listen
9 | from wxpy.api.bot import Bot
10 | from app.common import function
11 | from app.server import userDb, TextMsgHandle
12 | '''
13 | 微信个人服务器类
14 | '''
15 |
16 |
17 | class ServerController(object):
18 | def __init__(self, init=False):
19 | # 初始化机器人
20 | self.bot = Bot(init)
21 | self.bot.enable_puid("wxpy_puid.pkl")
22 | self.common = function.CommonFn()
23 | self.userdbser = userDb.User()
24 | self.textmsg = TextMsgHandle.TextMsg()
25 |
26 | # 存储所有朋友
27 | self.friends = []
28 |
29 | # 获取朋友列表
30 | self._get_friend()
31 |
32 | def _get_friend(self):
33 | friends = self.bot.friends()
34 | # 遍历所有好友,进行存储和更新好友信息
35 | friendpuid = set()
36 |
37 | for friend in friends:
38 | # 判断重复的puid
39 | if friend.puid in friendpuid:
40 | continue
41 |
42 | friendpuid.add(friend.puid)
43 | tmp_friends = self.bot.friends().search(puid=friend.puid)
44 |
45 | for tmp_friend in tmp_friends:
46 |
47 | # 机器人自己不加入
48 | if tmp_friend.raw["UserName"] == self.bot.self.raw["UserName"]:
49 | continue
50 |
51 | # 刷新当前数据库好友信息
52 | self._actionUserInfo(tmp_friend)
53 |
54 | def start(self):
55 | print("【" + self.bot.self.raw["NickName"] + "】登录成功")
56 | listen(self.bot, self.friends)
57 | self.bot.join()
58 |
59 | def replay(self):
60 | @self.bot.register()
61 | def print_others(msg):
62 | print(msg)
63 |
64 | @self.bot.register(self.friends)
65 | def reply_my_friend(msg):
66 | # 添加好友的提示
67 | if msg.type == "Note":
68 | return ''
69 |
70 | if msg.type != "Text":
71 | return "暂时支持文本格式的"
72 |
73 | # 发送的文本信息
74 | if msg.type == "Text":
75 | self.textmsg.start(msg)
76 |
77 | @self.bot.register(msg_types="Friends")
78 | def auto_accept_friends(msg):
79 | if "top" in msg.text.lower():
80 | new_friend = msg.card.accept()
81 |
82 | # 对添加的用户进行保存
83 | self._actionUserInfo(new_friend)
84 |
85 | new_friend.send(
86 | '您好,已经接受好友请求了\n访问 https://github.com/Topthinking/wxPython 查看更多'
87 | )
88 |
89 | def _actionUserInfo(self, friend):
90 | """
91 | 添加用户
92 | nick_name,user_name,puid,add_time
93 | 更新用户
94 | nick_name,user_name,puid,update_time,id
95 | """
96 | curTime = int(time.mktime(datetime.datetime.now().timetuple()))
97 | # 判定该添加的朋友之前是否存在备注
98 | if friend.raw["RemarkName"] == '':
99 | # 添加新的朋友到数据库
100 | param = (friend.raw["NickName"], friend.raw["UserName"],
101 | friend.puid, curTime)
102 | remarkName = self.userdbser.insertUserGetInertId(param)
103 | self.bot.core.set_alias(
104 | userName=friend.raw["UserName"], alias=remarkName)
105 | else:
106 | # 更新
107 | # 1.先查询是否存在该用户 存在就更新 否则就添加
108 | param = (friend.raw["RemarkName"], )
109 | info = self.userdbser.isExistUser(param)
110 |
111 | if info is None:
112 | # 添加新的朋友到数据库
113 | param = (friend.raw["NickName"], friend.raw["UserName"],
114 | friend.puid, curTime)
115 | remarkName = self.userdbser.insertUserGetInertId(param)
116 | self.bot.core.set_alias(
117 | userName=friend.raw["UserName"], alias=remarkName)
118 | else:
119 | param = (friend.raw["NickName"], friend.raw["UserName"],
120 | friend.puid, curTime, friend.raw["RemarkName"])
121 | self.userdbser.updateUserInfo(param)
122 |
123 | self.friends.append(friend)
124 |
--------------------------------------------------------------------------------
/app/server/subscribe.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from app.server import douyuServer
4 |
5 |
6 | class SubscribeHandle(object):
7 | def __init__(self, data, msg):
8 | self.data = data
9 | self.msg = msg
10 | self._diffSub()
11 | pass
12 |
13 | def _diffSub(self):
14 | res = False
15 | for sub in self.data:
16 | if sub["name"] == "斗鱼直播":
17 | # 连接斗鱼数据查询
18 | douyuSer = douyuServer.DouyuServer(self.msg)
19 |
20 | # 根据roomID号爬取斗鱼直播情况
21 | douyuSer.liveDataByRoomId()
22 | res = True
23 |
24 | if not res:
25 | self.msg.chat.send("待开发")
26 |
--------------------------------------------------------------------------------
/app/server/userDb.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from app.db import DBmain
3 |
4 |
5 | class User(object):
6 |
7 | def __init__(self):
8 | self.db = DBmain.DBModel()
9 | pass
10 |
11 | def isExistUser(self, param):
12 | sql = ' SELECT * FROM user WHERE id = %s ';
13 | return self.db.exeOneMySQL(sql, param)
14 |
15 | def insertUserGetInertId(self, param):
16 | sql = " INSERT INTO user (nick_name,user_name,puid,add_time) values(%s,%s,%s,%s) "
17 | data = self.db.insertMySQLById(sql, param)
18 | return data["id"]
19 |
20 | def updateUserInfo(self, param):
21 | sql = " UPDATE user set nick_name=%s,user_name=%s,puid=%s,update_time=%s WHERE id=%s "
22 | return self.db.updateMySQL(sql, param)
23 |
24 | def getUserInfoByUserName(self, param):
25 | sql = " SELECT * FROM user WHERE user_name = %s ";
26 | return self.db.exeOneMySQL(sql, param)
27 |
28 | def getToalUserInfo(self):
29 | sql = " SELECT * FROM user ";
30 | return self.db.exeAllMySQL(sql)
31 |
32 | def getUserSubInfo(self, param):
33 | sql = " SELECT s.name,s.id FROM user_sub as us \
34 | INNER JOIN subscribe as s \
35 | ON us.subscribe_id = s.id \
36 | WHERE us.uid = %s and us.status=1 "
37 | return self.db.exeAllMySQL(sql, param)
38 |
39 | def getSubInfo(self, param):
40 | sql = " SELECT * FROM subscribe WHERE name = %s or id = %s "
41 | return self.db.exeOneMySQL(sql, param)
42 |
43 | def InsertUserSubInfo(self, param):
44 | sql = " INSERT INTO user_sub (uid,subscribe_id,status) values(%s,%s,%s) "
45 | self.db.insertMySQL(sql, param)
46 |
47 | def updateUserSubInfo(self, param):
48 | sql = " UPDATE user_sub SET status = %s WHERE uid = %s and subscribe_id = %s "
49 | self.db.updateMySQL(sql, param)
50 |
51 | def isSubUserInfo(self, param):
52 | sql = " SELECT * FROM user_sub WHERE uid = %s and subscribe_id = %s "
53 | return self.db.exeOneMySQL(sql, param)
54 |
55 | def getSubList(self):
56 | sql = " SELECT * FROM subscribe WHERE status=1 "
57 | return self.db.exeAllMySQL(sql)
58 |
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | 使用wxpy爬取需求信息发送微信
2 | ==============================
3 |
4 | 技术栈:
5 |
6 | python3.6 + pip3 + wxpy + wechat_sender + urllib + bs4 +pymysql
7 |
8 | 下载 (运行`python3.6 `)
9 | 如果安装报错,请用pip安装指定模块,对于的wxpy的学习,请github自行搜索
10 |
11 | git clone https://github.com/Topthinking/wxPython.git
12 |
13 | cd wxPython
14 |
15 | python main.py
16 |
17 | 2017年6月25日
18 |
19 | * 初次提交,本地数据进行斗鱼主播的直播情况查询
20 |
21 | 2017年6月27日
22 |
23 | * 1.使用pymysql来动态捕获查询数据
24 | * 2.同时扩展了库与库之间的关系,待优化...
25 |
26 | 2017年6月28日
27 |
28 | * 1.数据的增删改查
29 | * 2.回复格式为 dy:[名称]:[房间号]:[别名] 即可完成添加或者修改,
30 | * 例如回复: dy:yyf:58428:rua ,
31 | * 结果就是更新rua别名,那么就可以回复rua获取房间号58428的直播情况
32 | * 可以回复多个别名,他们以英文的逗号隔开,比如 dy:yyf:58428:rua,胖头鱼
33 | * 3.优化sql语句对数据库的直接操作,防止sql注入
34 | * 4.同时处理了输入格式错误返回的信息
35 |
36 | 2017年6月30日
37 |
38 | * 1.加入订阅功能,具体回复:"我的订阅" 查看详情
39 | * 2.放出数据库表结构,在doc目录下
40 |
41 | 说明
42 |
43 | * 本项目主要学习Python爬虫,配合微信发送爬取信息,使得学习不会那么枯燥
44 |
45 | * 如果觉得不错的话,您可以点右上角 "Star" 支持一下 谢谢! ^_^
46 |
47 | * 如有问题请直接在 Issues 中提,或者您发现问题并有非常好的解决方案,欢迎 PR 👍
48 |
49 | ** 扫描二维码,验证信息输入'top' **
50 |
51 | .. image:: top.jpg
52 |
53 | 效果截图
54 |
55 | .. image:: show.png
56 |
57 | .. image:: sub.png
58 |
59 | 词汇截图
60 |
61 | .. image:: word.png
62 |
--------------------------------------------------------------------------------
/doc/show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/doc/show.png
--------------------------------------------------------------------------------
/doc/spider.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat MySQL Data Transfer
3 |
4 | Source Server : top
5 | Source Server Version : 50556
6 | Source Database : spider
7 |
8 | Target Server Type : MYSQL
9 | Target Server Version : 50556
10 | File Encoding : 65001
11 |
12 | Date: 2017-06-30 14:34:39
13 | */
14 |
15 | SET FOREIGN_KEY_CHECKS=0;
16 |
17 | -- ----------------------------
18 | -- Table structure for `dyLiveRoom`
19 | -- ----------------------------
20 | DROP TABLE IF EXISTS `dyLiveRoom`;
21 | CREATE TABLE `dyLiveRoom` (
22 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
23 | `name` varchar(100) DEFAULT NULL,
24 | `roomId` int(11) DEFAULT NULL,
25 | `alias` varchar(3000) DEFAULT NULL,
26 | PRIMARY KEY (`id`),
27 | UNIQUE KEY `roomId` (`roomId`) USING HASH,
28 | KEY `alias` (`alias`(255)) USING BTREE
29 | ) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
30 |
31 | -- ----------------------------
32 | -- Records of dyLiveRoom
33 | -- ----------------------------
34 | INSERT INTO `dyLiveRoom` VALUES ('1', 'yyf', '58428', '鱼鱼风,歪歪爱抚,yyf,yyfyyf,胖头鱼,y,小僵尸,rua,huh,,yyfyyfyyf,ruarua,66666,200斤,姜计就计');
35 | INSERT INTO `dyLiveRoom` VALUES ('2', '8', '64609', '8,绿帽8,下面八,八师傅,下面师傅,下面,八路军');
36 | INSERT INTO `dyLiveRoom` VALUES ('3', 'pis', '532152', 'p,绿帽p,小树人,报警,绿色保护着妮,pis');
37 | INSERT INTO `dyLiveRoom` VALUES ('4', '单车', '339610', '毒奶,车长老,单车武士');
38 | INSERT INTO `dyLiveRoom` VALUES ('5', '威海', '491416', '威海大叔');
39 | INSERT INTO `dyLiveRoom` VALUES ('7', '820', '507882', '乌鲁鲁,820,566,八老板,小乌贼,噜噜噜,乌露露,呜呜呜,露露,倚天');
40 | INSERT INTO `dyLiveRoom` VALUES ('25', 'zsmj', '52876', '方丈,马甲,zsmj');
41 | INSERT INTO `dyLiveRoom` VALUES ('26', '这是哪位啊', '980511', '美女');
42 | INSERT INTO `dyLiveRoom` VALUES ('27', '绅士', '45662', '破嘴,魔兽');
43 | INSERT INTO `dyLiveRoom` VALUES ('28', '红叶动漫', '326183', '红叶动漫');
44 | INSERT INTO `dyLiveRoom` VALUES ('29', '随机', '664795', '随机1');
45 | INSERT INTO `dyLiveRoom` VALUES ('30', '随机', '66475', '随机2');
46 | INSERT INTO `dyLiveRoom` VALUES ('31', '天使焦', '97376', '猪皇,猪,天使焦,天使宝宝,猪仔');
47 | INSERT INTO `dyLiveRoom` VALUES ('32', '岁月', '58674', '疯了,碧霞祠,阿西吧,我都醉了');
48 | INSERT INTO `dyLiveRoom` VALUES ('33', '岁月', '58624', 'logout,开机,关机');
49 | INSERT INTO `dyLiveRoom` VALUES ('34', '卡卡', '55353', '卡露露,卡露露,卡卡,卡师傅,噜噜噜噜噜,良智');
50 | INSERT INTO `dyLiveRoom` VALUES ('35', '冷冷', '20360', '喝冷水,冷冷,冷了个冷');
51 | INSERT INTO `dyLiveRoom` VALUES ('36', '主播', '36548', 'ruyrty,bhbj');
52 |
53 | -- ----------------------------
54 | -- Table structure for `subscribe`
55 | -- ----------------------------
56 | DROP TABLE IF EXISTS `subscribe`;
57 | CREATE TABLE `subscribe` (
58 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
59 | `name` varchar(100) DEFAULT NULL,
60 | `status` tinyint(4) NOT NULL DEFAULT '1',
61 | `desc` varchar(3000) DEFAULT NULL,
62 | PRIMARY KEY (`id`)
63 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
64 |
65 | -- ----------------------------
66 | -- Records of subscribe
67 | -- ----------------------------
68 | INSERT INTO `subscribe` VALUES ('1', '斗鱼直播', '1', null);
69 |
70 | -- ----------------------------
71 | -- Table structure for `user`
72 | -- ----------------------------
73 | DROP TABLE IF EXISTS `user`;
74 | CREATE TABLE `user` (
75 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
76 | `nick_name` varchar(300) DEFAULT NULL,
77 | `user_name` varchar(3000) DEFAULT NULL,
78 | `puid` varchar(30) DEFAULT NULL,
79 | `add_time` int(11) DEFAULT NULL,
80 | `update_time` int(11) DEFAULT NULL,
81 | PRIMARY KEY (`id`)
82 | ) ENGINE=InnoDB AUTO_INCREMENT=128 DEFAULT CHARSET=utf8;
83 |
84 | -- ----------------------------
85 | -- Table structure for `user_sub`
86 | -- ----------------------------
87 | DROP TABLE IF EXISTS `user_sub`;
88 | CREATE TABLE `user_sub` (
89 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
90 | `uid` int(11) DEFAULT NULL,
91 | `subscribe_id` int(11) DEFAULT NULL,
92 | `status` tinyint(4) NOT NULL DEFAULT '1',
93 | PRIMARY KEY (`id`)
94 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
--------------------------------------------------------------------------------
/doc/sub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/doc/sub.png
--------------------------------------------------------------------------------
/doc/top.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/doc/top.jpg
--------------------------------------------------------------------------------
/doc/word.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Topthinking/wxPython/d64f107e6b05a8238f9643d4c3f992c4c4d87357/doc/word.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 主入口文件
4 | """
5 | from app.server.main import ServerController
6 |
7 | if __name__ == '__main__':
8 | wx_server = ServerController(True)
9 | wx_server.replay()
10 | wx_server.start()
11 |
--------------------------------------------------------------------------------
/send.py:
--------------------------------------------------------------------------------
1 | from app.server.send_update_notify import VerUpdateSend
2 |
3 | if __name__ == '__main__':
4 | wx_send = VerUpdateSend(True)
5 | wx_send.sendMsg("欢迎使用top机器人,更多信息访问https://github.com/Topthinking/wxPython/")
6 |
--------------------------------------------------------------------------------