阿健的爬爬|微信端实时获取睿思最新相亲帖

兄弟!
是不是还单身?
想不想找女朋友?
想不想拉着她在西安的街头走一走,呜哦呜哦?
直到所有的灯都熄灭了,也不停留?

你会说,当然想,可是我在西电啊!
人家的校缘,那可都是“爱”!
我们的校媛,呸,猿,都是“唉”啊!

还好我们有睿思,有论坛,有相亲帖!
但是!
刚看上一个漂亮的小姐姐,想加微信撩,人家就结帖了,结帖了!
嗯?不知道结帖啥意思,看图!

对!就是这样!
人家已经被身披金甲圣衣,脚踏七彩祥云的盖世英雄给追到手了!
那你的余生是不是就只能找个男的凑合过日子了?
不!
身为肩负拯救世界重任的好心人,也就是我,不会让这种事发生的!
喏!
现在你可以在微信端实时接收最新的帖子啦!
她只要一在缘聚睿思版块发出求偶信号,你就可以在第!一!时!间!腆着个大脸过去撩了!

效果如下:

sorry,放错图了,是下面这张!

微信端效果

只要经过一些简单的配置,就可以享受这种黄金VIP级的待遇了!

没办法,谁让我人好,下面我就开始整了!

参考文档与博客

[1] BeautifulSoup中文文档
[2] itchat应用教程
[3] 校招提醒机器人-肖洒

环境部署

Anaconda是一个开源的python发行版本,个人习惯用python3,所以用的是Anaconda3。下载并安装好Anaconda3之后,python3、python3常用的依赖包、开发环境就都有了,开发环境习惯用jupyter notebook,当然其他的也可以。

另外还要用到两个包,BeautifulSoup和itchat,分别用于页面解析、与微信端交互,用pip安装,方法如下:

pip3 install beautifulsoup4
pip3 install itchat

解析相亲帖

某位女嘉宾的帖子是这样的


既有文本,又有照片,所以,按照套路,先导入所有要用到的包

from bs4 import BeautifulSoup#解析页面,第三方包
import urllib.request#请求网页
import itchat#用于微信端交互,第三方包
import time#定时器,python自带
import os#用于创建文件夹,python自带
import shutil#用于递归删除文件夹,python自带

解析页面,这里就直接引用大神校招提醒机器人-肖洒的代码了

def getPageContent(url):
    #伪装浏览器
    headers = {
        #浏览器信息,我用的是chrome
        'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
        #因为睿思论坛要先登录才能访问相亲帖,故要加入cookie,每个人的cookie都不同
        'Cookie' : 'Q8qA_2132_saltkey=Qdmt1tYy; Q8qA_2132_lastvisit=1529493180; Q8qA_2132_ulastactivity=4a18XdrzuW602gpzpKQEU5prg6bxSTeIM7hEYMDp7k6uJ%2BnogwMZ; Q8qA_2132_lastcheckfeed=304070%7C1529496798; Q8qA_2132_myrepeat_rr=R0; Q8qA_2132_auth=770aHvS7Tt2zInpFLb4FtNeIrYgHBY5rjKxZPFoXgWGhYTec%2BPuWoM19uou%2BdGLELy%2BnLJKub8Fg8Opp%2FJnNnHmM64E; Q8qA_2132_home_diymode=1; Q8qA_2132_nofavfid=1; Q8qA_2132_smile=4D1; Q8qA_2132_visitedfid=217D13D110; Q8qA_2132_st_t=304070%7C1529503019%7Cd72f8f898362e189f2b2780ed6e60c93; Q8qA_2132_forum_lastvisit=D_106_1529500683D_110_1529500694D_217_1529503019; Q8qA_2132_st_p=304070%7C1529503185%7C00734d0bcbe0384484f7216ada21fa02; Q8qA_2132_viewid=tid_945811; Q8qA_2132_sid=Pb9XCX; Q8qA_2132_lip=10.170.41.52%2C1529503691; Q8qA_2132_lastact=1529503776%09misc.php%09patch'
    }  
    #请求页面
    req = urllib.request.Request(url=url,headers=headers)
    try:
        res = urllib.request.urlopen(req)
    except urllib.error.URLError as e:
        return e
    page_content = res.read()
    #用lxml方式解析网页
    page_content=BeautifulSoup(page_content,"lxml")
    return page_content

先分析一下这个网页,既有文本,又有图片,先分析文本怎么爬。

定位到文本对应的网页元素,发现不同的字体对应不同的标签,但所有文本都在td标签下,即上图中箭头所指。只要想办法定位到相应的td标签下,用get_text()就可以得到所有文本了。但直接使用get_text()方法还会包含一些“最后发帖由谁在什么时间完成”之类的杂七杂八的文字,所以在代码中要对这些无关文字再删除。

对于图片,我们先定位图片的url,它长这样

./data/attachment/forum/201805/15/212638i0ktdwi1c9298wix.jpg

没有以http打头,一看就是相对路径,但相对路径浏览器不能识别哇,怎么得到绝对路径?

考虑到当前的url,也就是地址栏中的地址,它是这样什儿的:

http://rs.xidian.edu.cn/forum.php?mod=viewthread&tid=937063&extra=page%3D1%26filter%3Dlastpost%26orderby%3Dlastpost

而./data又表示先跳到上一级再定位到data目录,所以图片在服务器中完整的绝对路径应该是把http://rs.xidian.edu.cn/后面的内容替换成data/attachment/forum/201805/15/212638i0ktdwi1c9298wix.jpg,即

http://rs.xidian.edu.cn/data/attachment/forum/201805/15/212638i0ktdwi1c9298wix.jpg

写一个函数来实现这种替换功能

def urlJoin(urlCur, urlImg):
    
    #urlCur = 'http://rs.xidian.edu.cn/forum.php?mod=viewthread&tid=947526&extra=page%3D1%26filter%3Dlastpost%26orderby%3Dlastpost&page=1'
    #urlImg = './data/attachment/forum/201806/20/235708qtq25ommzqqruoa9.jpg'

    a = urlCur.split('/')

    b = urlImg.split('/')

    url = ''
    for i in a[:-1]:
        url += i + '/'

    for i in b[1:]:
        url += i + '/'
    
    return url[:-1]

现在,文本的内容和图片的地址我们都知道怎么爬取了,写个函数来实现它:

#urlCur为当前帖子的url,titleCur为帖子标题,nth为当前帖子是第几个人
def getInfo(urlCur, titleCur, nth):
    #解析网页
    page_content = getPageContent(urlCur)
    #定位td标签
    contents = page_content.find_all('td',class_='t_f')

    subpage = contents[0]
    
    #定位图片,把所有图片的url放到imageList中
    images = subpage.select('ignore_js_op')
    imageList = []
    for i in images:
        urlImg = i.find_all('img')[0].get('file')
        imageList.append(urlJoin(urlCur, urlImg))
    #删除无关文字
    while(subpage.i!=None):
        subpage.i.extract()
    while(subpage.ignore_js_op!=None):
        subpage.ignore_js_op.extract()
    
    info = subpage.get_text().strip()
    
    text = '『缘聚睿思【%d】——阿健的爬虫』\n\n' % nth
    text += '标题:' + titleCur + '\n\n'
    #删除无关的回车和空格,得到最终的文本text
    infoSplits = info.splitlines()
    for tt in infoSplits:
        if len(tt.strip()) == 0:
            infoSplits.remove(tt)

    for tt in infoSplits:
        text += tt + '\n'
    
    return text, imageList

好,对于文本,我们可以直接使用了,但图片的话要先下载下来才能使用。下载之前,我们先在当前目录创建一个文件夹

def mkdir(path):
    
    # 去除首位空格
    path=path.strip()
    # 去除尾部 \ 符号
    path=path.rstrip("\\")
 
    # 判断路径是否存在
    isExists=os.path.exists(path)
 
    # 要是存在,先删掉
    text = ''
    if  isExists:
        shutil.rmtree(path)
        text += ' has been deleted and'
    #创建文件夹    
    os.makedirs(path) 
 
    print(path + text + ' created successfully!')

再把这个宝宝所有的照片下载下来

# 传入照片url列表和文件夹名,下载照片,返回照片数
def downloadImgs(imageList, pathName):
    # 如果没有照片,返回照片数0
    if len(imageList) == 0:
        return 0
    # 创建文件夹
    mkdir(pathName)
    # 照片id,保存时取名用
    imgID = 0
    # 保存所有照片
    for image in imageList:
        imgID += 1
        urllib.request.urlretrieve(image, "%s/%d.jpg" % (pathName,imgID))
        
    numImgs = imgID
    # 返回照片数
    return numImgs

好了,当前这个宝宝的文本和图片我们都有了,考虑一下怎么发送到微信。我用了itchat这个包,登录后,可以把文本和图片发送给自己、好友和群聊,功能很强大,详情请参考itchat应用教程校招提醒机器人-肖洒的通俗解释。直接上代码:

'''
输入要发送的文本,图片路径,图片数量,发送对象
com=1,发送给自己
com=2,发送给好友
com=3,发送给群聊
'''
def wx(info, pathName, numImgs, com):
    
    itchat.auto_login(hotReload = True)# 可设置hotReload = True
    if com == 1:
        userName = 'filehelper'
    elif com == 2:
        userName = itchat.search_friends(name=u'硕士-徐赛')[0]["UserName"]
    else:
        i = itchat.get_chatrooms(update=True)
        name = "这一家子不简单"
        iRoom = itchat.search_chatrooms(name)
        for room in iRoom:
            if room['NickName'] == name:
                userName = room['UserName']
            break
     
    itchat.send_msg(info, userName)
    if numImgs == 0:
        itchat.send_msg('【TA暂时没有美照】', userName)
    else:
        for i in range(0, numImgs):
            path = pathName + '/' + str(i+1) + '.jpg'
            itchat.send_image(path,toUserName=userName)

这个函数运行时,会像微信电脑版一样提醒你在手机端登录,登录后就能自动把信息发送到指定对象了。

好,现在,对某个宝宝,我们可以爬取信息并发送到微信了,再考虑爬取其他宝宝的信息。回到缘聚睿思版块,按帖子发布时间排序,它是这样的

缘聚睿思

我们只爬取普通帖,不爬取投票帖(就是图中洗澡尿尿的那个,我也是醉了),区别就在于标题前面的图标不同。那就通过普通帖的图标,定位到该帖,我们要得到3个信息,该帖的标题、id和url。

标题就不用说了,url也好说,就是为了跳转到帖子内部去爬取文本内容和图片的,最重要的是id,每个帖子都有自己的id。因为我们要循环爬取帖子,为了避免重复抓取,必须要在爬取前判断该帖是否已经爬过,所以一定到得到每个帖子的唯一标识id!

# 论坛网址和每次要爬取的帖子数量
# 输出每个帖子的url、id、标题
def getUrlList(urlHome, numInfo):
    page_content = getPageContent(urlHome)
    subContents = page_content.find_all('img',{'src':'static/image/common/folder_new.gif'})
    urlList = []
    idList = []
    titleList = []
    for i in subContents:
        urlList.append('http://rs.xidian.edu.cn/' + i.parent.get('href'))
        idList.append(i.parent.parent.parent.parent.get('id'))
        titleList.append(i.parent.parent.parent.find_all('a',{'class':'s xst'})[0].get_text())
    return urlList[:numInfo],idList[:numInfo],titleList[:numInfo]

再写一个函数,来实现得到所有宝宝帖子的链接、爬取每个宝宝的信息、把信息发送到微信的功能。

# 输入:论坛地址,爬取过的宝宝的id记录,这是第几个宝宝,要爬几个宝宝,发送给谁
# 返回:爬取过的宝宝的id记录,这是第几个宝宝
def xdLoveEachTime(urlHome, idList, nth, numInfo,com):
    [urlList,curIdList,curTitleList] = getUrlList(urlHome, numInfo)
    for urlCur,idCur,titleCur in zip(urlList,curIdList,curTitleList):
        if idCur in idList:
            continue
        else:
            idList.append(idCur)
            [info, imageList] = getInfo(urlCur,titleCur, nth)
            pathName = 'images'
            numImgs = downloadImgs(imageList, pathName)
            wx(info,pathName,numImgs,com)
            nth += 1
    return idList,nth

好,只要给定输入,运行xdLoveEachTime函数,就能在微信端获取每个宝宝的信息了,但我们希望能实时获取最新宝宝的信息,那就加个定时器,每隔一段时间运行一次,保证能拿到第一手的资料。

写一个主函数,把前面所有的功能都封装好,每次要爬几个人、发送给谁等,完全由这个主函数控制,不再需要去修改其他函数的信息

# 输入:论坛网址,发送对象,要爬取几个人,隔多长时间爬取一次
def xdLove(urlHome,com=1,numInfo=1,sleepTime=60):
    idList = []
    nth = 1
    # 这里可以改成while(true)死循环
    for i in range(1000):
        [idList,nth] = xdLoveEachTime(urlHome,idList,nth,numInfo,com)
        print('阿健的爬虫已爬取' + str(i+1) + '次')
        time.sleep(sleepTime)

最后,运行主函数就可以了

# 注意论坛的网址一定是这个,这是按发帖时间排序的
urlHome = 'http://rs.xidian.edu.cn/forum.php?mod=forumdisplay&fid=217&filter=author&orderby=dateline'
xdLove(urlHome)

后台的运行界面是这样的

后台界面

微信端效果参考前面的图片。

至此,我们已经实现了从微信端实时获取睿思最新相亲帖的功能了。现在,你就可以等着喜欢的女嘉宾登场了,是不是有种翻牌儿的感觉~

不过,还是很多地方需要改进一下的:

  • 获取的宝宝是男是女都有可能,我希望每次推荐的宝宝都是女生

  • 即使是在普通帖子中,也会有很多租房帖子之类奇葩帖,我不想看到这些东西

  • 我希望帖主对帖子更新后,我也能看到更新信息。比如,某位女嘉宾希望找一米八的,但后来降低了要求,更新了帖子,改成了一米二的,那我就符合条件啦~

前两个功能可能会加一些自然语言处理的算法来预测一下,再判断是否过滤,还是很有挑战性的;第三个功能其实还不确定是否能看到更新帖,这个就再说吧~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • python实现微信接口(itchat) 安装 sudo pip install itchat 登录 itchat...
    爱撒谎的男孩阅读 12,726评论 2 64
  • 我的外婆今年83岁,她的一口牙我从来没有看过,听说当年30岁的时候就掉光了,耳朵要贴着说话才听得到,眼睛长年自然滴...
    窗外飘香阅读 625评论 6 4
  • what's the point?有什么意义? nature 加the 本质性质 不加冠词表示大自然 in nat...
    辣呜辣死我了阅读 116评论 0 0
  • 深圳龙岗,人来人往的马路旁,矗立着一栋十几层高的楼房。朴素的外观,简单的风格,没有任何意外,在大道两侧千篇一律着。...
    氧气是个地铁阅读 374评论 1 1
  • 遇见他是她的幸运!于是趁着现在还有力气去闹去折腾,去做自己喜欢的事,去追自己喜欢的人,无须在意一切,只为了多年以后...
    陌心人mo阅读 290评论 6 1