python编写的新浪微博爬虫

最近实验室安排了个任务,写一个新浪微博的爬虫,抓取大家的微博内容进行分析。

话说都快毕业了,最近还在一家通信设备商实习(工资好少啊),无奈只能抽出晚上的时间来写这个程序。

本来想用开源的爬虫的,于是尝试了nutch和heritrix。nutch性能太不稳定了,老是出问题。heritrix功能多,复杂,跑起来也慢。

当看到这两篇博客后(http://kcclub.kingsoft.com/home.php?mod=space&uid=93&do=blog&id=890)(http://1.wklken.sinaapp.com/?p=177),决定干脆自己写个爬虫吧。

这程序花了我6个晚上(其实大多数时间都在学习python语言。。。还有格式规范化。。。),现在拿出来和大家分享下吧。

如果有什么问题,请通过邮件和我联系(zhengyi.bupt@qq.com),我会及时更改(毕竟要交差么)。

程序运行方式:保存所有代码后,打开Main.py,修改LoginName为你的新浪微博帐号,PassWord为你的密码。运行Main.py,程序会在当前目录下生成CrawledPages文件夹,并保存所有爬取到的文件在这个文件夹中。

马上要毕业找工作季了,在此攒点rp,希望offer能好又多。


1. 执行文件,文件名Main.py

[python]  view plain copy ?
  1. #!/usr/bin/env python  
  2. #coding=utf8  
  3.   
  4.   
  5. '''''Author: Zheng Yi 
  6. Email: zhengyi.bupt@qq.com'''  
  7.   
  8.   
  9. import WeiboCrawl  
  10.   
  11.     
  12. if __name__ == '__main__':  
  13.     weiboLogin = WeiboCrawl.WeiboLogin('LoginName''PassWord')  
  14.     if weiboLogin.Login() == True:  
  15.         print "The WeiboLogin module works well!"  
  16.   
  17.     #start with my blog :)  
  18.     webCrawl = WeiboCrawl.WebCrawl('http://weibo.com/yaochen')  
  19.     webCrawl.Crawl()  
  20.     del webCrawl  

2. 主类,文件名WeiboCrawl.py

[python]  view plain copy ?
  1. #!/usr/bin/env python  
  2. #coding=utf8  
  3.   
  4.   
  5. '''''Author: Zheng Yi 
  6. Email: zhengyi.bupt@qq.com'''  
  7.   
  8.   
  9. import urllib2  
  10. import cookielib  
  11. import threading  
  12. import os  
  13. import WeiboEncode  
  14. import WeiboSearch  
  15. import TextAnalyze  
  16.   
  17.   
  18. pagesContent = []           #html content of downloaded pages  
  19. textContent = []            #main text content of downloaded pages  
  20. triedUrl = []               #all tried urls, including failed and success  
  21. toTryUrl = []               #urls to be try  
  22. failedUrl = []              #urls that fails to download  
  23.   
  24.   
  25. class WeiboLogin:  
  26.     "WeiboLogin class is for Weibo login, cookie, etc."  
  27.       
  28.     def __init__(self, user, pwd, enableProxy = False):  
  29.         "Constructor of class WeiboLogin."  
  30.   
  31.         print "Initializing WeiboLogin..."  
  32.         self.userName = user  
  33.         self.passWord = pwd  
  34.         self.enableProxy = enableProxy  
  35.         print "UserName:", user  
  36.         print "Password:", pwd  
  37.           
  38.         self.serverUrl = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=dW5kZWZpbmVk&client=ssologin.js(v1.3.18)&_=1329806375939"  
  39.         self.loginUrl = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.1)"  
  40.         self.postHeader = {'User-Agent''Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11'}  
  41.   
  42.   
  43.     def Login(self):  
  44.         "Run this function to laungh the login process"  
  45.       
  46.         self.EnableCookie(self.enableProxy)  
  47.           
  48.         serverTime, nonce = self.GetServerTime()  
  49.         postData = WeiboEncode.PostEncode(self.userName, self.passWord, serverTime, nonce)  
  50.         print "Post data length:\n", len(postData)  
  51.   
  52.         req = urllib2.Request(self.loginUrl, postData, self.postHeader)  
  53.         print "Posting request..."  
  54.         result = urllib2.urlopen(req)  
  55.         text = result.read()  
  56.         print "Post result page length: ", len(text)  
  57.           
  58.         try:  
  59.             loginUrl = WeiboSearch.sRedirectData(text)  
  60.             urllib2.urlopen(loginUrl)  
  61.         except:  
  62.             print 'Login error!'  
  63.             return False  
  64.               
  65.         print 'Login sucess!'  
  66.         return True  
  67.   
  68.            
  69.     def GetServerTime(self):  
  70.         "Get server time and nonce, which are used to encode the password"  
  71.           
  72.         print "Getting server time and nonce..."  
  73.         serverData = urllib2.urlopen(self.serverUrl).read()  
  74.         print serverData  
  75.   
  76.         try:  
  77.                 serverTime, nonce = WeiboSearch.sServerData(serverData)  
  78.                 return serverTime, nonce  
  79.         except:  
  80.                 print 'Get server time & nonce error!'  
  81.                 return None  
  82.   
  83.   
  84.     def EnableCookie(self, enableProxy):  
  85.         "Enable cookie & proxy (if needed)."  
  86.           
  87.         cookiejar = cookielib.LWPCookieJar()  
  88.         cookie_support = urllib2.HTTPCookieProcessor(cookiejar)  
  89.   
  90.         if enableProxy:  
  91.             proxy_support = urllib2.ProxyHandler({'http':'http://xxxxx.pac'})  
  92.             opener = urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler)  
  93.             print "Proxy enabled"  
  94.         else:  
  95.             opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)  
  96.   
  97.         urllib2.install_opener(opener)  
  98.   
  99.   
  100. class WebCrawl:  
  101.     "WebCrawl class is for crawling the Weibo"  
  102.   
  103.     def __init__(self, beginUrl, maxThreadNum = 10, maxDepth = 2, thLifetime = 10, saveDir = "." +os.sep + "CrawledPages"):  
  104.         "Initialize the class WebCrawl"  
  105.           
  106.         toTryUrl.append(beginUrl)  
  107.         self.maxThreadNum = maxThreadNum  
  108.         self.saveDir = saveDir  
  109.         self.maxDepth = maxDepth  
  110.         self.thLifetime = thLifetime  
  111.   
  112.         self.triedPagesNum = 0  
  113.         self.threadPool = []  
  114.   
  115.         if not os.path.exists(self.saveDir):  
  116.             os.mkdir(self.saveDir)  
  117.   
  118.         self.logFile = open(self.saveDir + os.sep + 'log.txt','w')  
  119.   
  120.   
  121.     def Crawl(self):  
  122.         "Run this function to start the crawl process"  
  123.           
  124.         global toTryUrl  
  125.   
  126.         for depth in range(self.maxDepth):  
  127.             print 'Searching depth ', depth, '...'  
  128.             self.DownloadAll()  
  129.             self.UpdateToTry()  
  130.   
  131.   
  132.     def DownloadAll(self):  
  133.         "Download all urls in current depth"  
  134.           
  135.         global toTryUrl  
  136.         iDownloaded = 0  
  137.           
  138.         while iDownloaded < len(toTryUrl):  
  139.             iThread = 0  
  140.             while iThread < self.maxThreadNum and iDownloaded + iThread < len(toTryUrl):  
  141.                 iCurrentUrl = iDownloaded + iThread  
  142.                 pageNum = str(self.triedPagesNum)  
  143.                 self.DownloadUrl(toTryUrl[iCurrentUrl], pageNum)  
  144.   
  145.                 self.triedPagesNum += 1  
  146.                 iThread += 1  
  147.                   
  148.             iDownloaded += iThread  
  149.               
  150.             for th in self.threadPool:  
  151.                 th.join(self.thLifetime)  
  152.                   
  153.             self.threadPool = []  
  154.               
  155.         toTryUrl = []  
  156.   
  157.       
  158.     def DownloadUrl(self, url, pageNum):  
  159.         "Download a single url and save"  
  160.           
  161.         cTh = CrawlThread(url, self.saveDir, pageNum, self.logFile)  
  162.         self.threadPool.append(cTh)  
  163.         cTh.start()  
  164.   
  165.   
  166.     def UpdateToTry(self):  
  167.         "Update toTryUrl based on textContent"  
  168.           
  169.         global toTryUrl  
  170.         global triedUrl  
  171.         global textContent  
  172.           
  173.         newUrlList = []  
  174.   
  175.         for textData in textContent:  
  176.             newUrlList += WeiboSearch.sUrl(textData)  
  177.           
  178.         toTryUrl = list(set(newUrlList) - set(triedUrl))  
  179.         pagesContent = []  
  180.         textContent = []  
  181.   
  182.   
  183. class CrawlThread(threading.Thread):  
  184.     "CrawlThread class is derived from threading.Thread, to create a thread."  
  185.   
  186.     thLock = threading.Lock()  
  187.   
  188.     def __init__(self, url, saveDir, pageNum, logFile):  
  189.         "Initialize the CrawlThread"  
  190.           
  191.         threading.Thread.__init__(self)  
  192.         self.url = url  
  193.         self.pageNum = pageNum  
  194.         self.fileName = saveDir + os.sep + pageNum + '.htm'  
  195.         self.textName = saveDir + os.sep + pageNum + '.txt'  
  196.         self.logFile = logFile  
  197.         self.logLine = 'File: ' + pageNum + '  Url: '+ url    
  198.   
  199.   
  200.     def run(self):  
  201.         "rewrite the run() function"  
  202.           
  203.         global failedUrl  
  204.         global triedUrl  
  205.         global pagesContent  
  206.         global textContent  
  207.   
  208.         try:  
  209.             htmlContent = urllib2.urlopen(self.url).read()              
  210.             transText = TextAnalyze.textTransfer(htmlContent)  
  211.               
  212.             fOut = open(self.fileName, 'w')  
  213.             fOut.write(htmlContent)  
  214.             fOut.close()  
  215.             tOut = open(self.textName, 'w')  
  216.             tOut.write(transText)  
  217.             tOut.close()  
  218.   
  219.         except:  
  220.             self.thLock.acquire()  
  221.             triedUrl.append(self.url)  
  222.             failedUrl.append(self.url)  
  223.             sFailed = 'Failed!   ' + self.logLine  
  224.             print sFailed  
  225.             self.logFile.write(sFailed + '\n')  
  226.             self.thLock.release()  
  227.             return None  
  228.           
  229.         self.thLock.acquire()  
  230.         pagesContent.append(htmlContent)  
  231.         textContent.append(transText)  
  232.         triedUrl.append(self.url)  
  233.         sSuccess = 'Success!  ' + self.logLine  
  234.         print sSuccess  
  235.         self.logFile.write(sSuccess + '\n')  
  236.         self.thLock.release()  

3. 加密函数,文件名WeiboEncode.py

[html]  view plain copy ?
  1. #!/usr/bin/env python  
  2. #coding=utf8  
  3.   
  4.   
  5. '''Author: Zheng Yi  
  6. Email: zhengyi.bupt@qq.com'''  
  7.   
  8.   
  9. import urllib  
  10. import base64  
  11. import hashlib  
  12.   
  13.   
  14. def PostEncode(userName, passWord, serverTime, nonce):  
  15.     "Used to generate POST data"  
  16.           
  17.     encodedUserName = GetUserName(userName)  
  18.     encodedPassWord = GetPassword(passWord, serverTime, nonce)  
  19.     postPara = {  
  20.         'entry': 'weibo',  
  21.         'gateway': '1',  
  22.         'from': '',  
  23.         'savestate': '7',  
  24.         'userticket': '1',  
  25.         'ssosimplelogin': '1',  
  26.         'vsnf': '1',  
  27.         'vsnval': '',  
  28.         'su': encodedUserName,  
  29.         'service': 'miniblog',  
  30.         'servertime': serverTime,  
  31.         'nonce': nonce,  
  32.         'pwencode': 'wsse',  
  33.         'sp': encodedPassWord,  
  34.         'encoding': 'UTF-8',  
  35.         'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',  
  36.         'returntype': 'META'  
  37.     }  
  38.     postData = urllib.urlencode(postPara)  
  39.     return postData  
  40.   
  41.   
  42. def GetUserName(userName):  
  43.     "Used to encode user name"  
  44.       
  45.     userNameTemp = urllib.quote(userName)  
  46.     userNameEncoded = base64.encodestring(userNameTemp)[:-1]  
  47.     return userNameEncoded  
  48.   
  49.   
  50. def GetPassword(passWord, serverTime, nonce):  
  51.     "Used to encode user password"  
  52.       
  53.     pwdTemp1 = hashlib.sha1(passWord).hexdigest()  
  54.     pwdTemp2 = hashlib.sha1(pwdTemp1).hexdigest()  
  55.     pwdTemp3 = pwdTemp2 + serverTime + nonce  
  56.     pwdEncoded = hashlib.sha1(pwdTemp3).hexdigest()  
  57.     return pwdEncoded  

4. 查找函数,文件名WeiboSearch.py

[python]  view plain copy ?
  1. #!/usr/bin/env python  
  2. #coding=utf8  
  3.   
  4.   
  5. '''''Author: Zheng Yi 
  6. Email: zhengyi.bupt@qq.com'''  
  7.   
  8.   
  9. import re  
  10. import json  
  11.   
  12.   
  13. def sServerData(serverData):  
  14.     "Search the server time & nonce from server data"  
  15.       
  16.     p = re.compile('\((.*)\)')  
  17.     jsonData = p.search(serverData).group(1)  
  18.     data = json.loads(jsonData)  
  19.     serverTime = str(data['servertime'])  
  20.     nonce = data['nonce']  
  21.     print "Server time is:", serverTime  
  22.     print "Nonce is:", nonce  
  23.     return serverTime, nonce  
  24.   
  25.   
  26. def sRedirectData(text):  
  27.     p = re.compile('location\.replace\(\'(.*?)\'\)')  
  28.     loginUrl = p.search(text).group(1)  
  29.     return loginUrl  
  30.   
  31.   
  32. def sUrl(htmlData):  
  33.     iMainBegin = htmlData.find('<div class="feed_lists" node-type="feed_list">')  
  34.     iMainEnd = htmlData.find('<div node-type="lazyload" class="W_loading">')  
  35.     mainData = htmlData[iMainBegin:iMainEnd]  
  36.     p = re.compile('href=\"(\/[a-zA-Z0-9\/\%]*?)\"')  
  37.     #p = re.compile('href=\"(http:\/\/weibo.com\/[a-zA-Z]*?)\"')  
  38.     semiUrlList = p.findall(mainData)  
  39.     urlList = []  
  40.     for url in semiUrlList:  
  41.         urlList.append('http://weibo.com' + url)  
  42.     return urlList  

5. 简单的html内容分析、格式转换,文件名TextAnalyze.py

[python]  view plain copy ?
  1. #!/usr/bin/env python  
  2. #coding=utf8  
  3.   
  4.   
  5. '''''Author: Zheng Yi 
  6. Email: zhengyi.bupt@qq.com'''  
  7.   
  8.   
  9. def textTransfer(htmlContent):  
  10.     "Decode the main part of html"  
  11.   
  12.     line = textExtract(htmlContent)  
  13.     print 'line:', line  
  14.     if line != None:  
  15.         transText = textTransfer(line)  
  16.         return transText  
  17.     else:  
  18.         return None  
  19.   
  20.   
  21. def textExtract(htmlContent):  
  22.     "Extract the main part from html"  
  23.   
  24.     lines = htmlContent.splitlines()  
  25.     for line in lines:  
  26.         if line.startswith('<script>STK && STK.pageletM && STK.pageletM.view({"pid":"pl_content_[homeFeed|hisFeed]"'):  
  27.             return line  
  28.         else:  
  29.             return None  
  30.   
  31.   
  32. def textTransfer(line):  
  33.     "Decode the main part"  
  34.       
  35.     iText = line.find('html":"')  
  36.     if iText > 0:  
  37.         transText = line[iText + 7: -12].encode("utf-8").decode('unicode_escape').encode("utf-8").replace("\\", "")  
  38.         return transText  
  39.     else:  
  40.         return None 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值