[Python爬虫] Selenium爬取新浪微博移动端热点话题及评论 (下)

来源:互联网 发布:vuze mac怎么用 编辑:程序博客网 时间:2024/05/29 10:14
这篇文章主要讲述了使用python+selenium爬取新浪微博的热点话题和评论信息。其中使用该爬虫的缺点是效率极低,傻瓜式的爬虫,不能并行执行等,但是它的优点是采用分析DOM树结构分析网页源码并进行信息爬取,同时它可以通过浏览器进行爬取中间过程的演示及验证码的输入。这篇文章对爬虫的详细过程就不再论述了,主要是提供可运行的代码和运行截图即可。希望文章对你有所帮助吧~

参考文章
[python爬虫] Selenium爬取新浪微博内容及用户信息
[Python爬虫] Selenium爬取新浪微博客户端用户信息、热点话题及评论 (上)
[Python爬虫] 在Windows下安装PIP+Phantomjs+Selenium
[Python爬虫] Selenium实现自动登录163邮箱和Locating Elements介绍
http://selenium-python.readthedocs.org/locating-elements.html

实现过程
运行截图如下所示,它通过调用Firefox浏览器,然后输入移动端网址自动登陆新浪微博,它会自动输入用户名及密码,但需要用户在我设置暂停20秒内输入验证码。登陆后它会自动跳转到微博主题搜索页面,当用户输入关键词"欢乐颂"后,就会对返回的微博信息及评论进行爬取了,爬取过程中需要注意翻页即可。



运行结果
运行结果如下图所示:两个文件,一个是微博内容评论对应的URL,一个是爬取URL中的评论信息。





源代码
源代码如下:

# coding=utf-8"""  Created on 2016-04-24 @author: Eastmount功能: 爬取新浪微博用户的信息及微博评论网址:http://weibo.cn/ 数据量更小 相对http://weibo.com/正确的方法是把所有的URL都获取再依次访问"""    import time            import re            import os    import sys  import codecs  import shutilimport urllib from selenium import webdriver        from selenium.webdriver.common.keys import Keys        import selenium.webdriver.support.ui as ui        from selenium.webdriver.common.action_chains import ActionChains#先调用无界面浏览器PhantomJS或Firefox    #driver = webdriver.PhantomJS(executable_path="G:\phantomjs-1.9.1-windows\phantomjs.exe")    driver = webdriver.Firefox()wait = ui.WebDriverWait(driver,10)#全局变量 文件操作读写信息inforead = codecs.open("SinaWeibo_List_best_1.txt", 'r', 'utf-8')infofile = codecs.open("SinaWeibo_Info_best_1.txt", 'w', 'utf-8')#********************************************************************************#                            第一步: 登陆weibo.cn #        该方法针对weibo.cn有效(明文形式传输数据) weibo.com见学弟设置POST和Header方法#                LoginWeibo(username, password) 参数用户名 密码#********************************************************************************def LoginWeibo(username, password):    try:        #输入用户名/密码登录        print u'准备登陆Weibo.cn网站...'        driver.get("http://login.weibo.cn/login/")        elem_user = driver.find_element_by_name("mobile")         elem_user.send_keys(username) #用户名        elem_pwd = driver.find_element_by_xpath("/html/body/div[2]/form/div/input[2]")        elem_pwd.send_keys(password)  #密码 name=password_6785        #elem_rem = driver.find_element_by_name("remember")        #elem_rem.click()             #记住登录状态        #重点:暂停时间输入验证码(http://login.weibo.cn/login/ 手机端需要)        time.sleep(20)        #点击submit按钮登陆方式或输入回车键登陆方式        #elem_sub = driver.find_element_by_name("submit")        #elem_sub.click()                      elem_pwd.send_keys(Keys.RETURN)        time.sleep(2)                #获取Coockie         print driver.current_url        print driver.get_cookies()  #获得cookie信息 dict存储        print u'输出Cookie键值对信息:'        for cookie in driver.get_cookies():             #print cookie            for key in cookie:                print key, cookie[key]                            #driver.get_cookies()类型list 仅包含一个元素cookie类型dict        print u'登陆成功...'                    except Exception,e:              print "Error: ",e    finally:            print u'End LoginWeibo!\n\n'#**********************************************************************************************#                  第二步: 访问个人页面http://weibo.cn/5824697471并获取信息#                                VisitPersonPage()#        编码常见错误 UnicodeEncodeError: 'ascii' codec can't encode characters文件utf-8编码#**********************************************************************************************def VisitPersonPage(user_id):    try:        global infofile       #全局文件变量        url = "http://weibo.com/" + user_id        driver.get(url)        print u'准备访问个人网站.....', url        print u'个人详细信息'                #用户id        print u'用户id: ' + user_id        #昵称 关注数 粉丝数 微博数 个人资料其它信息        #URL http://weibo.cn/5824697471/follow                       except Exception,e:              print "Error: ",e    finally:            print u'VisitPersonPage!\n\n'        #********************************************************************************#                  第三步: 访问http://weibo.cn/search/ (手机端) 页面搜索热点信息#                         爬取微博信息及评论,注意评论翻页的效果和微博的数量#********************************************************************************    def GetComment(key):    try:        global infofile       #全局文件变量        driver.get("http://weibo.cn/search/")        print u'搜索热点主题关键词:', key        #输入主题并点击搜索        item_inp = driver.find_element_by_xpath("//div[@class='c']/form/div/input") #name=keyword        item_inp.send_keys(key)        item_inp.send_keys(Keys.RETURN)    #采用点击回车直接搜索        #内容        #content = driver.find_elements_by_xpath("//div[@class='content clearfix']/div/p")        comment = driver.find_elements_by_xpath("//a[@class='cc']")        content = driver.find_elements_by_xpath("//div[@class='c']")        print content        all_comment_url = []               #存储所有文件URL        i = 0        j = 0        infofile.write(u'开始:\r\n')        print u'长度', len(content)        while i<len(content):            #print content[i].text            if (u'收藏' in content[i].text) and (u'评论' in content[i].text): #过滤其他标签                print content[i].text                infofile.write(u'微博信息:\r\n')                infofile.write(content[i].text + '\r\n')                div_id = content[i].get_attribute("id")                print div_id                while(1):  #存在其他包含class=cc 如“原文评论”                    url_com = comment[j].get_attribute("href")                    if ('comment' in url_com) and ('uid' in url_com):                        print url_com                        infofile.write(u'评论信息:\r\n')                        infofile.write(url_com+'\r\n')                        all_comment_url.append(url_com)    #保存到变量里                        j = j + 1                        break                    else:                        j = j + 1                                i = i + 1        #http://weibo.cn/search/?pos=search        print driver.current_url                #python中文转换url编码 urllib.quote(key) urllib.unquote转回来        #转码失败        #http://weibo.cn/search/mblog?hideSearchFrame=&keyword=欢乐颂&page=2        #url = "http://weibo.cn/search/mblog?hideSearchFrame=&keyword="+ key_url + "&page=2"        #获取10个下页        N = 2        while N<=10:            #后面采用换页 第一次为方便给大家解决方法就采用获取搜索框id回车访问            url_get = driver.find_element_by_xpath("//div[@id='pagelist']/form/div/a")            url = url_get.get_attribute("href")             print url #获取下页            driver.get(url)            comment = driver.find_elements_by_xpath("//a[@class='cc']")            content = driver.find_elements_by_xpath("//div[@class='c']")            print content            i = 0            j = 0                        #第一个<a class='cc' href>是多余的            print u'长度', len(content)            infofile.write(u'\r\n下页:\r\n')            while i<len(content):                #print content[i].text                if (u'收藏' in content[i].text) and (u'评论' in content[i].text):                    print content[i].text                    infofile.write(u'微博信息:\r\n')                    infofile.write(content[i].text + '\r\n')                    #获取该信息id值 通过id获取评论超链接                    #先获取:<div id="M_Du3npzqSd" class="c">                     #再获取:<a class="cc" href="http://weibo.cn/comment/#cmtfrm"></a>                    div_id = content[i].get_attribute("id")                    print div_id                    '''                    url = driver.find_elements_by_xpath("//div[@id=" + div_id + "]/a")                    print url                    for u in url:                        print u.get_attribute("href")                    '''                    while(1):  #存在其他包含class=cc 如“原文评论”                        url_com = comment[j].get_attribute("href")                        if ('comment' in url_com) and ('uid' in url_com):                            print url_com                            infofile.write(u'评论信息:\r\n')                            infofile.write(url_com + '\r\n')                            all_comment_url.append(url_com)                            j = j + 1                            break                        else:                            j = j + 1                i = i + 1            N = N + 1        else:            print u'结束爬取评论URL 对齐while循环'                    #方位评论URL并进行爬取        print u'\n\n评论'        infocomment = codecs.open("SinaWeibo_Info_best_2.txt", 'w', 'utf-8')        for url in all_comment_url:            print url            driver.get(url)            #driver.refresh()            time.sleep(2)            infocomment.write(url+'\r\n')            test = driver.find_elements_by_class_name('c')            print len(test)            #Error:  Message: Element not found in the cache -            #perhaps the page has changed since it was looked up            #http://www.51testing.com/html/21/n-862721-2.html            #异常的说明已经很明显了:在cache中找不到元素,在元素被找到之后页面变换了。            #这就说明,当当前页面发生跳转之后,存在cache中的关于这个页面的元素也被清空了。            k = 0            while k<len(test):                 print test[k].text                infocomment.write(test[k].text + '\r\n')                k = k + 1            infocomment.write('\r\n')        infocomment.close()                                          except Exception,e:              print "Error: ",e    finally:            print u'VisitPersonPage!\n\n'        print '**********************************************\n'                #*******************************************************************************#                                程序入口 预先调用#         注意: 因为sina微博增加了验证码,但是你用Firefox登陆输入验证码#         直接跳转到明星微博那部分,即: http://weibo.cn/guangxianliuyan#*******************************************************************************    if __name__ == '__main__':    #定义变量    username = '15201615157'             #输入你的用户名    password = '*********'               #输入你的密码    #操作函数    LoginWeibo(username, password)       #登陆微博    #在if __name__ == '__main__':引用全局变量不需要定义 global inforead 省略即可    print 'Read file:'    user_id = inforead.readline()    while user_id!="":        user_id = user_id.rstrip('\r\n')        print user_id        VisitPersonPage(user_id)         #访问个人页面http://weibo.cn/guangxianliuyan        user_id = inforead.readline()        #break    #搜索热点微博 爬取评论    key = u'欢乐颂'     GetComment(key)        infofile.close()    inforead.close()        




登陆部分核心代码
其中登陆部分的核心代码及对应DOM树结构分析如下:
#调用Firefox浏览器 
driver =  webdriver.Firefox()
driver.get("http://login.weibo.cn/login/")
#用户名
elem_user = driver.find_element_by_name("mobile") 
elem_user.send_keys(username)      
#密码 name=password_6785
elem_pwd = driver.find_element_by_xpath("/html/body/div[2]/form/div/input[2]")
elem_pwd.send_keys(password)      
#记住登录状态
elem_rem = driver.find_element_by_name("remember")
elem_rem.click()                              
#重点:暂停时间输入验证码(http://login.weibo.cn/login/ 手机端需要)
time.sleep(20)
#点击submit按钮登陆方式或输入回车键登陆方式
elem_sub = driver.find_element_by_name("submit")
elem_sub.click()              
elem_pwd.send_keys(Keys.RETURN)




为什么需要从移动端登陆呢?
新浪微博有两个入口:
        新浪微博登录常用接口:http://login.sina.com.cn/ 
        对应主界面:
http://weibo.com/
        但是个人建议采用手机端微博入口:http://login.weibo.cn/login/  
        对应主界面:http://weibo.cn/
因为在客户端登陆爬取微博评论信息时,它总是通过JavaScript动态加载的,需要点击按钮才能加载,单纯的获取评论的节点或使用正则表达式爬取评论部分的HTML源码,都是空值,所以采用移动端进行爬取。
它们的主要区别是移动端数据相对更简练,但是内容都基本一样,只是图片较小、关注粉丝数只能显示20页、个人信息缺失些等,供手机用户使用,但是信息是和客户端对应的。
如下图所示,它表示动态加载的评论,可以看到"href=javascript:void(0)"还有一些script函数实现的动态加载。




跳转页面下一页
常用的方法,如我前面的文章讲解爬取虎扑图片、生物预料中,都是通过分析URL的&构成进行的。新浪微博同样也是:
http://weibo.cn/search/mblog?hideSearchFrame=&keyword=欢乐颂&page=2
其中搜索关键词"欢乐颂",只需要修改page页面即可。但是"欢乐颂"中文字符转换为URL编码时总是报错,python使用中文转换url编码方法:urllib.quote(key)。
所以采用了第二种方法,获取下一页的URL,再进行driver.get(url)访问,循环N从2到10。
#获取下页
url_get = driver.find_element_by_xpath("//div[@id='pagelist']/form/div/a")
url = url_get.get_attribute("href")  
driver.get(url)

#评论URL
comment = driver.find_elements_by_xpath("//a[@class='cc']")
#微博内容 需过滤其它class=c 
content = driver.find_elements_by_xpath("//div[@class='c']")


重点获取URL队列依次爬取评论
由于新浪微博需要模拟登陆,所以获取微博的同时获取了评论的URL,但是这里使用的浏览器driver不能同时访问评论信息,因为它在循环中driver还在使用。换句话就是find_elements_by_xpath是获取多个值,当然你可以再开一个driver2,但也需要登陆,再driver2.get(url_comment)即可。
但常用的爬虫通常是有一个URL队列的概念,把爬取的评论URL都存储在一个队列或数组中。该程序循环先N从2到10,爬取10页的微博信息及评论URL,再依次爬取评论信息,如果获得了URL,也能爬取微博内容的。
关键:使用数组存储所有评论的URL队列,再一次driver.get(url)爬取所有微博及评论。
#方位评论URL并进行爬取
print u'\n\n评论'
infocomment = codecs.open("SinaWeibo_Info_best_2.txt", 'w', 'utf-8')
for url in all_comment_url:
      print url
      driver.get(url)

      #driver.refresh()
      time.sleep(2)
      infocomment.write(url+'\r\n')
      test = driver.find_elements_by_class_name('c')
      print len(test)
      k = 0
      while k<len(test): 
            print test[k].text
            infocomment.write(test[k].text + '\r\n')
            k = k + 1
      infocomment.write('\r\n')
infocomment.close()



错误Element not found in the cache
在爬取过程中可能会遇到错误:Error:  Message: Element not found in the cache - perhaps the page has changed since it was looked up
参考:http://www.51testing.com/html/21/n-862721-2.html
异常的说明解释:在cache中找不到元素,在元素被找到之后页面变换了。这就说明,当当前页面发生跳转之后,存在cache中的关于这个页面的元素也被清空了。
通过实验发现,它是使用driver.get(url)访问评论时,太快没有加载页面获取元素,采用的方法是time.sleep(2)显示2秒。希望有更好的解决方法~当然时间设置短点也行。


热门话题置顶
通过比较客户端和移动端的信息,会发现搜索微博热点,它在客户端首先显示的是最近关于该话题非常热门的微博,如"欢乐颂"蒋欣的状态等。





比较移动端和客户端微博信息
这是比较移动到和客户端的微博信息,信息基本是一致的,可能只是因为排序显示问题可能序号稍微微调,同时客户端也采用了热门话题置顶显示的一些推荐相关算法吧!如"一个五点之前就醒了的人....."






然后下面是具体的评论信息,可以发现也是对应的,但是通过手机端就可以显示评论信息,可以进行爬取,而客户端爬取结果为空。








PS:最后希望文章对你有所帮助!其实方法很简单,希望你能理解这种思想,如何分析HTML源码及DOM树结构,然后动态获取自己需要的信息。
(By:Eastmount 2016-05-06 深夜4点半  http://blog.csdn.net/eastmount/ )


1 0
原创粉丝点击