[python爬虫] Selenium爬取新浪微博内容及用户信息

感谢原作者

在进行自然语言处理、文本分类聚类、推荐系统、舆情分析等研究中,通常需要使用新浪微博的数据作为语料,这篇文章主要介绍如果使用Python和Selenium爬取自定义新浪微博语料。因为网上完整的语料比较少,而使用Selenium方法有点简单、速度也比较慢,但方法可行,同时能够输入验证码。希望文章对你有所帮助~

源码下载地址:http://download.csdn.net/detail/eastmount/9501273

爬取结果
首先可以爬取用户ID、用户名、微博数、粉丝数、关注数及微博信息。其中微博信息包括转发或原创、点赞数、转发数、评论数、发布时间、微博内容等等。如下图所示:


同时也可以爬取微博的众多用户的详细信息,包括基本信息、关注人ID列表和粉丝ID列表等等。如下图所示:



登录入口
新浪微博登录常用接口:
http://login.sina.com.cn/  
对应主界面:
http://weibo.com/
但是个人建议采用手机端微博入口: http://login.weibo.cn/login/   
对应主界面:http://weibo.cn/

其原因是手机端数据相对更轻量型,同时基本数据都齐全,可能缺少些个人基本信息,如"个人资料完成度"、"个人等级"等,同时粉丝ID和关注ID只能显示20页,但完全可以作为语料进行大部分的验证。

通过比较下面两张图,分别是 PC端 手机端,可以发现内容基本一致:



手机端下图所示,其中图片相对更小,同时内容更精简。




完整源码
下面代码主要分为三部分:
1.LoginWeibo(username, password) 登录微博
2.VisitPersonPage(user_id) 访问跟人网站,获取个人信息
3.获取微博内容,同时http://weibo.cn/guangxianliuyan?filter=0&page=1实现翻页
  1. # coding=utf-8  
  2.   
  3. """   
  4. Created on 2016-02-22 @author: Eastmount 
  5.  
  6. 功能: 爬取新浪微博用户的信息 
  7. 信息:用户ID 用户名 粉丝数 关注数 微博数 微博内容 
  8. 网址:http://weibo.cn/ 数据量更小 相对http://weibo.com/ 
  9.  
  10. """      
  11.   
  12. import time              
  13. import re              
  14. import os      
  15. import sys    
  16. import codecs    
  17. import shutil  
  18. import urllib   
  19. from selenium import webdriver          
  20. from selenium.webdriver.common.keys import Keys          
  21. import selenium.webdriver.support.ui as ui          
  22. from selenium.webdriver.common.action_chains import ActionChains  
  23.   
  24.   
  25. #先调用无界面浏览器PhantomJS或Firefox      
  26. #driver = webdriver.PhantomJS(executable_path="G:\phantomjs-1.9.1-windows\phantomjs.exe")      
  27. driver = webdriver.Firefox()      
  28. wait = ui.WebDriverWait(driver,10)  
  29.   
  30.   
  31. #全局变量 文件操作读写信息  
  32. inforead = codecs.open("SinaWeibo_List.txt"'r''utf-8')  
  33. infofile = codecs.open("SinaWeibo_Info.txt"'a''utf-8')  
  34.   
  35.   
  36. #********************************************************************************  
  37. #                  第一步: 登陆weibo.cn 获取新浪微博的cookie  
  38. #        该方法针对weibo.cn有效(明文形式传输数据) weibo.com见学弟设置POST和Header方法  
  39. #                LoginWeibo(username, password) 参数用户名 密码  
  40. #                             验证码暂停时间手动输入  
  41. #********************************************************************************  
  42.   
  43. def LoginWeibo(username, password):  
  44.     try:  
  45.         #**********************************************************************  
  46.         # 直接访问driver.get("http://weibo.cn/5824697471")会跳转到登陆页面 用户id  
  47.         #  
  48.         # 用户名<input name="mobile" size="30" value="" type="text"></input>  
  49.         # 密码 "password_4903" 中数字会变动,故采用绝对路径方法,否则不能定位到元素  
  50.         #  
  51.         # 勾选记住登录状态check默认是保留 故注释掉该代码 不保留Cookie 则'expiry'=None  
  52.         #**********************************************************************  
  53.           
  54.         #输入用户名/密码登录  
  55.         print u'准备登陆Weibo.cn网站...'  
  56.         driver.get("http://login.weibo.cn/login/")  
  57.         elem_user = driver.find_element_by_name("mobile")  
  58.         elem_user.send_keys(username) #用户名  
  59.         elem_pwd = driver.find_element_by_xpath("/html/body/div[2]/form/div/input[2]")  
  60.         elem_pwd.send_keys(password)  #密码  
  61.         #elem_rem = driver.find_element_by_name("remember")  
  62.         #elem_rem.click()             #记住登录状态  
  63.   
  64.         #重点: 暂停时间输入验证码  
  65.         #pause(millisenconds)  
  66.         time.sleep(20)  
  67.           
  68.         elem_sub = driver.find_element_by_name("submit")  
  69.         elem_sub.click()              #点击登陆  
  70.         time.sleep(2)  
  71.           
  72.         #获取Coockie 推荐 http://www.cnblogs.com/fnng/p/3269450.html  
  73.         print driver.current_url  
  74.         print driver.get_cookies()  #获得cookie信息 dict存储  
  75.         print u'输出Cookie键值对信息:'  
  76.         for cookie in driver.get_cookies():   
  77.             #print cookie  
  78.             for key in cookie:  
  79.                 print key, cookie[key]  
  80.                       
  81.         #driver.get_cookies()类型list 仅包含一个元素cookie类型dict  
  82.         print u'登陆成功...'  
  83.           
  84.           
  85.     except Exception,e:        
  86.         print "Error: ",e  
  87.     finally:      
  88.         print u'End LoginWeibo!\n\n'  
  89.   
  90.   
  91. #********************************************************************************  
  92. #                  第二步: 访问个人页面http://weibo.cn/5824697471并获取信息  
  93. #                                VisitPersonPage()  
  94. #        编码常见错误 UnicodeEncodeError: 'ascii' codec can't encode characters   
  95. #********************************************************************************  
  96.   
  97. def VisitPersonPage(user_id):  
  98.   
  99.     try:  
  100.         global infofile  
  101.         print u'准备访问个人网站.....'  
  102.         #原创内容 http://weibo.cn/guangxianliuyan?filter=1&page=2  
  103.         driver.get("http://weibo.cn/" + user_id)  
  104.   
  105.         #**************************************************************************  
  106.         # No.1 直接获取 用户昵称 微博数 关注数 粉丝数  
  107.         #      str_name.text是unicode编码类型  
  108.         #**************************************************************************  
  109.   
  110.         #用户id  
  111.         print u'个人详细信息'  
  112.         print '**********************************************'  
  113.         print u'用户id: ' + user_id  
  114.   
  115.         #昵称  
  116.         str_name = driver.find_element_by_xpath("//div[@class='ut']")  
  117.         str_t = str_name.text.split(" ")  
  118.         num_name = str_t[0]      #空格分隔 获取第一个值 "Eastmount 详细资料 设置 新手区"  
  119.         print u'昵称: ' + num_name   
  120.   
  121.         #微博数 除个人主页 它默认直接显示微博数 无超链接  
  122.         #Error:  'unicode' object is not callable  
  123.         #一般是把字符串当做函数使用了 str定义成字符串 而str()函数再次使用时报错  
  124.         str_wb = driver.find_element_by_xpath("//div[@class='tip2']")    
  125.         pattern = r"\d+\.?\d*"   #正则提取"微博[0]" 但r"(
    .?
    )"总含[]   
  126.         guid = re.findall(pattern, str_wb.text, re.S|re.M)  
  127.         print str_wb.text        #微博[294] 关注[351] 粉丝[294] 分组[1] @他的  
  128.         for value in guid:  
  129.             num_wb = int(value)  
  130.             break  
  131.         print u'微博数: ' + str(num_wb)  
  132.   
  133.         #关注数  
  134.         str_gz = driver.find_element_by_xpath("//div[@class='tip2']/a[1]")  
  135.         guid = re.findall(pattern, str_gz.text, re.M)  
  136.         num_gz = int(guid[0])  
  137.         print u'关注数: ' + str(num_gz)  
  138.   
  139.         #粉丝数  
  140.         str_fs = driver.find_element_by_xpath("//div[@class='tip2']/a[2]")  
  141.         guid = re.findall(pattern, str_fs.text, re.M)  
  142.         num_fs = int(guid[0])  
  143.         print u'粉丝数: ' + str(num_fs)  
  144.           
  145.   
  146.         #***************************************************************************  
  147.         # No.2 文件操作写入信息  
  148.         #***************************************************************************  
  149.   
  150.         infofile.write('=====================================================================\r\n')  
  151.         infofile.write(u'用户: ' + user_id + '\r\n')  
  152.         infofile.write(u'昵称: ' + num_name + '\r\n')  
  153.         infofile.write(u'微博数: ' + str(num_wb) + '\r\n')  
  154.         infofile.write(u'关注数: ' + str(num_gz) + '\r\n')  
  155.         infofile.write(u'粉丝数: ' + str(num_fs) + '\r\n')  
  156.         infofile.write(u'微博内容: ' + '\r\n\r\n')  
  157.           
  158.           
  159.         #***************************************************************************  
  160.         # No.3 获取微博内容  
  161.         # http://weibo.cn/guangxianliuyan?filter=0&page=1  
  162.         # 其中filter=0表示全部 =1表示原创  
  163.         #***************************************************************************  
  164.   
  165.         print '\n'  
  166.         print u'获取微博内容信息'  
  167.         num = 1  
  168.         while num <= 5:  
  169.             url_wb = "http://weibo.cn/" + user_id + "?filter=0&page=" + str(num)  
  170.             print url_wb  
  171.             driver.get(url_wb)  
  172.             #info = driver.find_element_by_xpath("//div[@id='M_DiKNB0gSk']/")  
  173.             info = driver.find_elements_by_xpath("//div[@class='c']")  
  174.             for value in info:  
  175.                 print value.text  
  176.                 info = value.text  
  177.   
  178.                 #跳过最后一行数据为class=c  
  179.                 #Error:  'NoneType' object has no attribute 'groups'  
  180.                 if u'设置:皮肤.图片' not in info:  
  181.                     if info.startswith(u'转发'):  
  182.                         print u'转发微博'  
  183.                         infofile.write(u'转发微博\r\n')  
  184.                     else:  
  185.                         print u'原创微博'  
  186.                         infofile.write(u'原创微博\r\n')  
  187.                           
  188.                     #获取最后一个点赞数 因为转发是后有个点赞数  
  189.                     str1 = info.split(u" 赞")[-1]  
  190.                     if str1:   
  191.                         val1 = re.match(r'
    (.?)
    ', str1).groups()[0]  
  192.                         print u'点赞数: ' + val1  
  193.                         infofile.write(u'点赞数: ' + str(val1) + '\r\n')  
  194.   
  195.                     str2 = info.split(u" 转发")[-1]  
  196.                     if str2:   
  197.                         val2 = re.match(r'
    (.?)
    ', str2).groups()[0]  
  198.                         print u'转发数: ' + val2  
  199.                         infofile.write(u'转发数: ' + str(val2) + '\r\n')  
  200.   
  201.                     str3 = info.split(u" 评论")[-1]  
  202.                     if str3:  
  203.                         val3 = re.match(r'
    (.?)
    ', str3).groups()[0]  
  204.                         print u'评论数: ' + val3  
  205.                         infofile.write(u'评论数: ' + str(val3) + '\r\n')  
  206.   
  207.                     str4 = info.split(u" 收藏 ")[-1]  
  208.                     flag = str4.find(u"来自")  
  209.                     print u'时间: ' + str4[:flag]  
  210.                     infofile.write(u'时间: ' + str4[:flag] + '\r\n')  
  211.   
  212.                     print u'微博内容:'  
  213.                     print info[:info.rindex(u" 赞")]  #后去最后一个赞位置  
  214.                     infofile.write(info[:info.rindex(u" 赞")] + '\r\n')  
  215.                     infofile.write('\r\n')  
  216.                     print '\n'  
  217.                 else:  
  218.                     print u'跳过', info, '\n'  
  219.                     break  
  220.             else:  
  221.                 print u'next page...\n'  
  222.                 infofile.write('\r\n\r\n')  
  223.             num += 1  
  224.             print '\n\n'  
  225.         print '**********************************************'  
  226.           
  227.           
  228.     except Exception,e:        
  229.         print "Error: ",e  
  230.     finally:      
  231.         print u'VisitPersonPage!\n\n'  
  232.         print '**********************************************\n'  
  233.           
  234.   
  235. #*******************************************************************************  
  236. #                                程序入口 预先调用  
  237. #*******************************************************************************  
  238.       
  239. if __name__ == '__main__':  
  240.   
  241.     #定义变量  
  242.     username = '1520161***'             #输入你的用户名  
  243.     password = '**********'               #输入你的密码  
  244.     user_id = 'guangxianliuyan'          #用户id url+id访问个人   
  245.   
  246.   
  247.     #操作函数  
  248.     LoginWeibo(username, password)      #登陆微博  
  249.   
  250.     #driver.add_cookie({'name':'name', 'value':'_T_WM'})  
  251.     #driver.add_cookie({'name':'value', 'value':'c86fbdcd26505c256a1504b9273df8ba'})  
  252.   
  253.     #注意  
  254.     #因为sina微博增加了验证码,但是你用Firefox登陆一次输入验证码,再调用该程序即可,因为Cookies已经保证  
  255.     #会直接跳转到明星微博那部分,即: http://weibo.cn/guangxianliuyan  
  256.       
  257.   
  258.     #在if __name__ == '__main__':引用全局变量不需要定义 global inforead 省略即可  
  259.     print 'Read file:'  
  260.     user_id = inforead.readline()  
  261.     while user_id!="":  
  262.         user_id = user_id.rstrip('\r\n')  
  263.         VisitPersonPage(user_id)         #访问个人页面  
  264.         user_id = inforead.readline()  
  265.         #break  
  266.       
  267.     infofile.close()  
  268.     inforead.close()  
  269.       
  270.       
PS:发现CSDN编辑器的BUG,只要包含( ) 如:r'
(.?)
'就会自动换行 (⊙o⊙)


登录页面
首先,为什么需要登录呢?
因为新浪微博很多数据如果不登录是不能获取或访问的,如微博的粉丝列表、个人详细信息、微博下一页等等,当你点击这些超链接时就会自动跳转到登录界面,这是开发者对其进行的保护措施。同时,各个公司都会提供API接口让开发者进行操作,但此处我是使用Selenium模拟浏览器操作进行爬取的。


其中登录如上图所示,函数LoginWeibo(username, password) 实现,它会自动打开浏览器并输入用户名和密码。在登录过程中由于会涉及到验证码,所以我采用暂停20秒,当用户手动输入验证码并且时间到后会自动点击按钮登录。核心代码如下:
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)       #密码
elem_sub = driver.find_element_by_name("submit")
elem_sub.click()              #点击登陆


如果你登陆过程中Python报错:
WebDriverException: Message: "Can't load the profile. Profile Dir:
猜测是Firefox版本问题,升级后出现的该问题,建议下载相对较老的版本,总体感觉只要Selenium、Python、Firefox版本一致就不会报错,可从下面链接中安装该版本Firefox。
下载地址:http://download.csdn.net/detail/mengh2016/7752097

那么,登录成功后,为什么就能访问或跳转到不同的页面呢?
因为登录成功后会保存Cookies或Session信息,此时用户就可以任意跳转访问了,否则会重新跳转会登录界面。这里使用Selenium的driver.get(url)实现跳转。

获取个人信息
首先很多网站设计都是 URL+用户ID 访问个人网站,如柳岩: http://weibo.cn/guangxianliuyan
故定义一个TXT文件列表包含,所有用户ID信息,依次通过读取文件爬取其微博信息:
user_id = inforead.readline()
while user_id!="":
    user_id = user_id.rstrip('\r\n')
    VisitPersonPage(user_id)         #访问个人页面
    user_id = inforead.readline()


其中用户ID列表在SinaWeibo_List.txt 中,如下所示:(明星)
  1. guangxianliuyan  
  2. zhangjiani  
  3. 1862829871  
  4. zmqd  
  5. houzimi  
  6. 3125046087  
  7. gezhaoen  
  8. 1877716733  
  9. ailleenmmm  
  10. linshenblog  
  11. superleoisme  
  12. 2638613703  
  13. duiersky  
  14. ws95  
  15. wuwei1003673996  
  16. wuxin  
  17. 1413971423  
  18. xiena  
  19. yangxinyu888  
  20. zhangyangguoer0418  
  21. liuyifeiofficial  

通过分析HTML源码,获取节点位置,通过Selenium函数定义位置获取信息,然后再通过正则表达式或字符串处理获取想要的值。如获取昵称:
str_name = driver.find_element_by_xpath("//div[@class='ut']")
#空格分隔 获取第一个值 "Eastmount 详细资料 设置 新手区"
str_t = str_name.text.split(" ")
num_name = str_t[0]     
print u'昵称: ' + num_name

再如括号之间数字内容:
#微博[294] 关注[351] 粉丝[294] 分组[1] @他的 
str_gz = driver.find_element_by_xpath("//div[@class='tip2']/a[1]")
guid = re.findall(pattern, str_gz.text, re.M)
num_gz = int(guid[0])
print u'关注数: ' + str(num_gz)




资料URL:http://weibo.cn/1644461042/info
关注URL:http://weibo.cn/1644461042/follow
粉丝URL:http://weibo.cn/1644461042/fans
但是手机端只能显示20页粉丝列表和关注列表。
点击"资料"可以获取个人详细信息、点击"关注[516]"可以获取关注列表,如果需要建立不同用户之间的关注网,个人建议通过关注表而不是粉丝表,因为关注表覆盖明星更大,而粉丝太多,构建的图太稀疏。个人信息如下图所示:


获取微博
微博URL:http://weibo.cn/guangxianliuyan?filter=0&page=1
通过分析如下URL链接,可以发现Page=n 表示访问第n页微博,从而实现跳转。filter=1表示原创,可以分析它对应的开头几个类型。再通过函数获取内容:
info = driver.find_elements_by_xpath("//div[@class='c']")

然后如果发布的微博以"转发了..."开头表示转发的微博,否则为原创微博,代码:
info.startswith(u'转发')

同时获取微博点赞数、转发数、时间等,其中因为转发会包括点赞数,故获取最后一个"赞[xxx]",然后通过正则表达式i获取括号之间内容。

str1 = info.split(u" 赞")[-1]
if str1: 
   val1 = re.match(, str1).groups()[0]
   print u'点赞数: ' + val1
   infofile.write(u'点赞数: ' + str(val1) + '\r\n')


微博都是以class='c'节点,故获取是有这类值,再进行字符串处理即可。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值