爬取燕山大学校园通知,并推送给qq群

爬取校园通知

首先爬取校园通知,做一个基本的爬虫即可。以下代码命名为ysuspider.py

import re
import requests
import pymysql
from pyquery import PyQuery as pq
import json

hds=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},\
{'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},\
{'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}]
    
def mysqlcon(newsurl,title,time):
    hosts= '127.0.0.1'  
    username = 'root'
    password = 'password'
    database = 'qq'
    charsets = 'utf8'
    connection = False
    findflag= True
    upflag=False
    try:
        conn = pymysql.connect(host = hosts,user = username,passwd = password,db = database,charset = charsets)
        cursor = conn.cursor()
        cursor.execute("set names "+charsets)
        connection = True           
    except Exception as e:
        print ("Cannot Connect To Mysql!/n '%s'"%e)    
    if connection:   
        cursor.execute('''CREATE TABLE IF NOT EXISTS qqbottable(newsurl varchar(255) default '1', title varchar(255) default '1', time varchar(255) default '1');''')
        if newsurl and title:
            sql_find = """select * from qqbottable where newsurl=%s"""
            findflag=cursor.execute(sql_find, newsurl)
            print ("数据库是否包含消息:%s"%findflag)
    if not findflag:            
        try:
            sql_up="""replace into qqbottable(newsurl, title, time) values(%s,%s,%s)"""
            upflag=cursor.execute(sql_up, (newsurl,title,time))
            print ("更新数据库:%s"% upflag)  
        except Exception as e:
            print ("更新数据库错误: %s"%e)
    return upflag           
def YSU_notices_spider():
    flag_workok=False
    url1='http://notice.ysu.edu.cn/'
    newscontents=requests.get(url=url1).content.decode('utf-8')
    d=pq(newscontents)
    asss=d('div.list')('li').items()
    for item in asss:
        newsurl=url1+item('a').attr('href')
        title=item('.list-txt-1').text()
        time=item('.list-date').text()       
        message="燕山大学"+time+"通知:\n"+title+"\n"+newsurl
        if mysqlcon(newsurl,title,time):
            print("开始发布")
           
            
    return flag_workok
if __name__=='__main__':
    flag_workok=YSU_notices_spider()
    print("爬取发布:%s"%flag_workok)

上面 YSU_notices_spider函数代表了爬取燕大通知页面的几个消息,用到了requests和pyquery。把爬取到的标题连接和时间存储到数据库中。下次检测数据库中是否含有连接,如果不含有,则发布数据并存到数据库中。发布数据用到了一个开源框架,qqbot。

  • 首先申请一个小号qq

  • pip install qqbot 安装qqbot,中间需要安装依赖,qqbot具体安装和使用方法参考https://github.com/pandolia/qqbot

  • 用小号qq扫码登录qqbot。

  • 设计发送函数。

    def sendmessage(mes): sendflag=False command=“send group 官方交流群 %s” %mes resp = BYTES2STR(Query(‘127.0.0.1’, 8188, SYSTEMSTR2BYTES(command))) if not resp: PRINT(‘无法连接 QQBot-Term 服务器’) elif not resp.strip(): PRINT(‘QQBot 命令格式错误’) else: PRINT(resp.strip()) sendflag=True

在函数YSU_notices_spider()中的print(“开始发布”)后边调用此函数即可。这样,做一个bat文件调用ysuspider.py,里边写python ysuspider.py和它放到同一个文件夹,并把快捷方式放到系统定时任务中就可以实现爬虫内容的定时爬取和推送了。

更好的方式,加入机器人自动聊天

读了一下qqbot源码和接口,发现这种发送信息的方式并不是官方推荐的,作者给出了消息发送接口。而且qqbot本身就是一直运行的,它也有定时任务接口。可以直接把上面代码作为插件放到qqbot中。即配置qqbot的v*.*.conf文件,将ysuspider.py去掉以下代码以后放到指定插件目录。如site-packages\qqbot\plugins.这个路径对代码中的调用有影响。

if name=='main': flag_workok=YSU_notices_spider() print(“爬取发布:%s”%flag_workok)

加入from qqbot import _bot as bot来导入qqbot。发送信息函数就可以变成

def sendmessage(mes):

contact=bot.List('group', '官方交流群')[0]   
sendsucc=bot.SendTo(contact, mes, resendOn1202=True)
print(sendsucc)

再做一个qqbot的插件调用修改后的代码pyYsuspider.py

from qqbot.utf8logger import DEBUG
from qqbot import QQBotSched as qqbotsched
from qqbot.utf8logger import INFO
import qqbot.plugins.ysuNotic as ysunotice
import qqbot.plugins.qqTulingBot as qqtuling
class g(object):
    pass

def onPlug(bot):
    g.t = bot.conf.pluginsConf.get(__name__, '16:00')
    g.hour, g.minute = g.t.split(':')   
    @qqbotsched(hour=g.hour, minute=g.minute)
    def schedRestart(_bot):
        #_bot.FreshRestart()
        flag_workok=ysunotice.YSU_notices_spider()
        print("爬取发布:%s"%flag_workok)
    INFO('已创建计划任务:每天 %s 执行燕大通知播报', g.t)

def onUnplug(bot):
    INFO('已删除计划任务:每天 %s 执行燕大通知播报)', g.t)
def onQQMessage(bot, contact, member, content):
    if bot.isMe(contact, member):
        return True
    # 当收到 QQ 消息时被调用
    # bot     : QQBot 对象,提供 List/SendTo/GroupXXX/Stop/Restart 等接口,详见文档第五节
    # contact : QContact 对象,消息的发送者
    # member  : QContact 对象,仅当本消息为 群或讨论组 消息时有效,代表实际发消息的成员
    # content : str 对象,消息内容    
    if '@ME' in content:       
        wenti = content.split('[@ME]')[-1]
        daan = qqtuling.Tulingmain(wenti)
        bot.SendTo(contact,'@'+member.name+"  "+daan)

函数中的onPlug(bot)是qqbot加载插件时运行,起到了一个定时任务的作用,装饰器qqbotsched设定每天循环执行的时间。
函数onQQMessage设定了有人@机器人时机器人的动作,调用了图灵机器人的接口。本文用的是http://www.tuling123.com的机器人,网上有很多聚合数据的图灵机器人,个人对聚合数据没什么好感,而且每天信息条数比这个少,所以就用的这个。原理都差不多,调用图灵机器人提供的web api即可,api的具体内容这里有介绍http://www.tuling123.com/help/h_cent_webapi.jhtml?nav=doc

Tulingmain代码如下。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import json
import requests
header={"User-Agent":'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36',"Content-Type":'text/html; charset=utf-8'}
def Tulingmain(text = '笑而不语'):

  #配置您申请的APPKey
  appkey = "****************"

  #1.问答
  return request1(appkey,"POST",text)
#问答
def request1(appkey, m="POST", text="笑而不语"):
    url = "http://www.tuling123.com/openapi/api"
    params = {
        "key" : appkey, #您申请到的本接口专用的APPKEY
        "info" : text, #要发送给机器人的内容,不要超过30个字符
        "loc" : "", #地点,如北京中关村
        "userid" : "", #1~32位,此userid针对您自己的每一个用户,用于上下文的关联

    }
    f=requests.post(url,params=params)
    res=f.json()
    if res:
        error_code = res["code"]
        if error_code ==40001:
            return "参数key错误"
        elif error_code ==40002:
            return "请求内容info为空"
        elif error_code ==40004:
            return "当天请求次数已使用完"
        elif error_code ==40007:
            return "数据格式异常" 
        elif error_code ==100000:
            #文本类
            #"code":100000,
            #"text":"你也好 嘻嘻"
            return  res["text"]
        elif error_code ==200000:
            #链接类
            #"code": 200000,
            #"text": "亲,已帮你找到结果",
            #"url": "http://m.image.so.com/i?q=%E5%B0%8F%E7%8B%97"
            result=res["text"]+res["url"]
            return result
        elif error_code ==302000:
            #新闻类
            #"code": 302000,
            #"text": "亲,已帮你找到结果",
            #"list": [{},{}]
            result=res["text"] 
            for item in res["list"]:
                result1="\n"+item["article"]+"("+item["source"]+")\n"+item["detailurl"]             
                result= result +result1              
            return result
        elif error_code ==200000:
            #列车飞机类
            result=res["text"]+res["url"]
            return result
        elif error_code ==308000:
            #菜谱类
            #"code": 302000,
            #"text": "亲,已帮你找到结果",
            #"list": [{},{}]
            result=res["text"] 
            for item in res["list"]:               
                result1="\n"+item["icon"]+item["name"]+"("+item["info"]+")\n"+item["detailurl"]             
                result= result +result1              
            return result            
        #if error_code == 0:
          #成功请求
          # print (res["result"])
          # return res['result']
          # print (res['result']['text'])
            #return res['result']['text']
        else:
            return "异常的功能"

    else:
        return "我的接口好像出错了"

改一下配置文件来调用这个插件。配置文件在C:\Users\Administrator.qqbot-tmp下.

See Also