【python网络编程】新浪爬虫:关键词搜索爬取微博数据
来源:互联网 发布:84cs域名升级访问升级 编辑:程序博客网 时间:2024/06/06 17:09
上学期参加了一个大数据比赛,需要抓取大量数据,于是我从新浪微博下手,本来准备使用新浪的API的,无奈新浪并没有开放关键字搜索的API,所以只能用爬虫来获取了。幸运的是,新浪提供了一个高级搜索功能,为我们爬取数据提供了一个很好的切入点。
在查阅了一些资料,参考了一些爬虫的例子后,得到大体思路:构造URL,爬取网页,然后解析网页
具体往下看~
登陆新浪微博,进入高级搜索,如图输入,之后发送请求会发现地址栏变为如下: http://s.weibo.com/weibo/%25E4%25B8%25AD%25E5%25B1%25B1%25E5%25A4%25A7%25E5%25AD%25A6®ion=custom:44:1&typeall=1&suball=1×cope=custom:2015-08-07-0:2015-08-08-0&Refer=g
解析如下:固定地址部分:http://s.weibo.com/weibo/
关键字二次UTF-8编码:%25E4%25B8%25AD%25E5%25B1%25B1%25E5%25A4%25A7%25E5%25AD%25A6
搜索地区:region=custom:44:1
搜索时间范围:timescope=custom:2015-08-07-0:2015-08-08-0
可忽略项:Refer=g
某次请求的页数:page=1(第一页可不加)
我们查看一下网页源代码看看有什么鬼:
小伙伴们第一次看到肯定大呼我的天啊,真的是看的眼花缭乱。
别着急,让我娓娓道来。
首先,我们定位到图示的地方,即出现字符串<script>STK && STK.pageletM && STK.pageletM.view({"pid":"pl_weibo_direct"的地方,此处即搜索到的微博页面的代码啦~
页面是unicode码,所以中文都不能正常显示~而且上面没有排版,才显得如此杂乱。
我们可以先对抓取到的页面处理一下,这时就要用到lxml的etree了,它可以将网页内容的结点构建成一棵树。
我们拿出其中一个结点出来看看:
<a class=\"W_texta W_fb\" nick-name=\"\u554a\u5be7\u5504\" href=\"http:\/\/weibo.com\/612364698\" target=\"_blank\" title=\"\u554a\u5be7\u5504\" usercard=\"id=1884932730&usercardkey=weibo_mp\"\t\tsuda-data=\"key=tblog_search_weibo&value=weibo_ss_1_name\" class=\"name_txt W_fb\">
在这个结点中,我们可以获取该条微博的博主的一些信息,如nick-name,微博地址href。
我们再看看另一个结点:
<p class=\"comment_txt\" node-type=\"feed_list_content\" nick-name=\"\u554a\u5be7\u5504\">\u8fd9\u4e48\u52aa\u529b \u5c45\u7136\u5012\u6570\u7b2c\u4e94 \u5509 \u4e0d\u884c\u6211\u8981\u8ffd\u56de\u6765 \u8d8a\u632b\u8d8a\u52c7 \u4e0d\u53ef\u4ee5\u81ea\u66b4\u81ea\u5f03 \u4e0d\u53ef\u4ee5\u8ba9\u8d1f\u9762\u60c5\u7eea\u8dd1\u51fa\u6765 \u83dc\u575a\u5f3a \u52a0\u6cb9\u52a0\u6cb9\u52a0\u6cb9 \u6211\u8981\u4e0a<em class=\"red\">\u4e2d\u5c71\u5927\u5b66<\/em> \u6211\u8981\u548c\u5c0f\u54c8\u5427\u4e00\u6240\u5927\u5b66 \u62fc\u4e86<\/p>
这个结点包含的数据即为微博的内容。
这样子就清晰很多了。至于如何搜索相应的结点,取得结点的属性和内容等,我们用的是xpath这个工具。
关于xpath,见文 http://blog.csdn.net/raptor/article/details/4516441
获得数据后,是数据的保存,我是将数据导入到excel中,用到的xlwt和xlrd这两个模块。
最后数据的效果(我搜集的信息比较具体,需要访问博主的个人主页获取,为便于大家阅读、理解,下面代码中删去了这部分):
代码:
# coding: utf-8'''以关键词收集新浪微博'''import wximport sysimport urllibimport urllib2import reimport jsonimport hashlibimport osimport timefrom datetime import datetimefrom datetime import timedeltaimport randomfrom lxml import etreeimport loggingimport xlwtimport xlrdfrom xlutils.copy import copyclass CollectData(): """数据收集类 利用微博高级搜索功能,按关键字搜集一定时间范围内的微博。 """ def __init__(self, keyword, startTime, interval='50', flag=True, begin_url_per = "http://s.weibo.com/weibo/"): self.begin_url_per = begin_url_per #设置固定地址部分 self.setKeyword(keyword) #设置关键字 self.setStartTimescope(startTime) #设置搜索的开始时间 #self.setRegion(region) #设置搜索区域 self.setInterval(interval) #设置邻近网页请求之间的基础时间间隔(注意:过于频繁会被认为是机器人) self.setFlag(flag) self.logger = logging.getLogger('main.CollectData') #初始化日志 ##设置关键字 ##关键字需解码后编码为utf-8 def setKeyword(self, keyword): self.keyword = keyword.decode('GBK','ignore').encode("utf-8") print 'twice encode:',self.getKeyWord() ##关键字需要进行两次urlencode def getKeyWord(self): once = urllib.urlencode({"kw":self.keyword})[3:] return urllib.urlencode({"kw":once})[3:] ##设置起始范围,间隔为1天 ##格式为:yyyy-mm-dd def setStartTimescope(self, startTime): if not (startTime == '-'): self.timescope = startTime + ":" + startTime else: self.timescope = '-' ##设置搜索地区 #def setRegion(self, region): # self.region = region ##设置邻近网页请求之间的基础时间间隔 def setInterval(self, interval): self.interval = int(interval) ##设置是否被认为机器人的标志。若为False,需要进入页面,手动输入验证码 def setFlag(self, flag): self.flag = flag ##构建URL def getURL(self): return self.begin_url_per+self.getKeyWord()+"&typeall=1&suball=1×cope=custom:"+self.timescope+"&page=" ##爬取一次请求中的所有网页,最多返回50页 def download(self, url, maxTryNum=4): hasMore = True #某次请求可能少于50页,设置标记,判断是否还有下一页 isCaught = False #某次请求被认为是机器人,设置标记,判断是否被抓住。抓住后,需要,进入页面,输入验证码 name_filter = set([]) #过滤重复的微博ID i = 1 #记录本次请求所返回的页数 while hasMore and i < 51 and (not isCaught): #最多返回50页,对每页进行解析,并写入结果文件 source_url = url + str(i) #构建某页的URL data = '' #存储该页的网页数据 goon = True #网络中断标记 ##网络不好的情况,试着尝试请求三次 for tryNum in range(maxTryNum): try: html = urllib2.urlopen(source_url, timeout=12) data = html.read() break except: if tryNum < (maxTryNum-1): time.sleep(10) else: print 'Internet Connect Error!' self.logger.error('Internet Connect Error!') self.logger.info('url: ' + source_url) self.logger.info('fileNum: ' + str(fileNum)) self.logger.info('page: ' + str(i)) self.flag = False goon = False break if goon: lines = data.splitlines() isCaught = True for line in lines: ## 判断是否有微博内容,出现这一行,则说明没有被认为是机器人 if line.startswith('<script>STK && STK.pageletM && STK.pageletM.view({"pid":"pl_weibo_direct"'): isCaught = False n = line.find('html":"') if n > 0: j = line[n + 7: -12].encode("utf-8").decode('unicode_escape').encode("utf-8").replace("\\", "") #去掉所有的\ ## 没有更多结果页面 if (j.find('<div class="search_noresult">') > 0): hasMore = False ## 有结果的页面 else: #此处j要decode,因为上面j被encode成utf-8了 page = etree.HTML(j.decode('utf-8')) ps = page.xpath("//p[@node-type='feed_list_content']") #使用xpath解析得到微博内容 addrs = page.xpath("//a[@class='W_texta W_fb']") #使用xpath解析得到博主地址 addri = 0 #获取昵称和微博内容 for p in ps: name = p.attrib.get('nick-name')#获取昵称 txt = p.xpath('string(.)')#获取微博内容 addr = addrs[addri].attrib.get('href') #获取微博地址 addri += 1 if(name != 'None' and str(txt) != 'None' and name not in name_filter): #导出数据到excel中 name_filter.add(name) oldWb = xlrd.open_workbook('weiboData.xls', formatting_info=True) oldWs = oldWb.sheet_by_index(0) rows = int(oldWs.cell(0,0).value) newWb = copy(oldWb) newWs = newWb.get_sheet(0) newWs.write(rows, 0, str(rows)) newWs.write(rows, 1, name) newWs.write(rows, 2, self.timescope) newWs.write(rows, 3, addr) newWs.write(rows, 4, txt) newWs.write(0, 0, str(rows+1)) newWb.save('weiboData.xls') print "save with same name ok" break lines = None ## 处理被认为是机器人的情况 if isCaught: print 'Be Caught!' self.logger.error('Be Caught Error!') self.logger.info('filePath: ' + savedir) self.logger.info('url: ' + source_url) self.logger.info('fileNum: ' + str(fileNum)) self.logger.info('page:' + str(i)) data = None self.flag = False break ## 没有更多结果,结束该次请求,跳到下一个请求 if not hasMore: print 'No More Results!' if i == 1: time.sleep(random.randint(3,8)) else: time.sleep(10) data = None break i += 1 ## 设置两个邻近URL请求之间的随机休眠时间,防止Be Caught sleeptime_one = random.randint(self.interval-25,self.interval-15) sleeptime_two = random.randint(self.interval-15,self.interval) if i%2 == 0: sleeptime = sleeptime_two else: sleeptime = sleeptime_one print 'sleeping ' + str(sleeptime) + ' seconds...' time.sleep(sleeptime) else: break ##改变搜索的时间范围,有利于获取最多的数据 def getTimescope(self, perTimescope): if not (perTimescope=='-'): times_list = perTimescope.split(':') start_date = datetime(int(times_list[-1][0:4]), int(times_list[-1][5:7]), int(times_list[-1][8:10]) ) start_new_date = start_date + timedelta(days = 1) start_str = start_new_date.strftime("%Y-%m-%d") return start_str + ":" + start_str else: return '-'def main(): logger = logging.getLogger('main') logFile = './collect.log' logger.setLevel(logging.DEBUG) filehandler = logging.FileHandler(logFile) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s') filehandler.setFormatter(formatter) logger.addHandler(filehandler) while True: ## 接受键盘输入 keyword = raw_input('Enter the keyword(type \'quit\' to exit ):') if keyword == 'quit': sys.exit() startTime = raw_input('Enter the start time(Format:YYYY-mm-dd):') #region = raw_input('Enter the region([BJ]11:1000,[SH]31:1000,[GZ]44:1,[CD]51:1):') interval = raw_input('Enter the time interval( >30 and deafult:50):') ##实例化收集类,收集指定关键字和起始时间的微博 cd = CollectData(keyword, startTime, interval) while cd.flag: print cd.timescope logger.info(cd.timescope) url = cd.getURL() cd.download(url) cd.timescope = cd.getTimescope(cd.timescope) #改变搜索的时间,到下一天 else: cd = None print '-----------------------------------------------------' print '-----------------------------------------------------' else: logger.removeHandler(filehandler) logger = None##if __name__ == '__main__':## main()
上面实现了数据的爬取,再结合上一篇文章中的模拟登录,就可以美美的抓数据啦~
- 【python网络编程】新浪爬虫:关键词搜索爬取微博数据
- 使用网页爬虫(高级搜索功能)搜集含关键词新浪微博数据
- Python-新浪微博爬虫采集数据
- Python爬虫:抓取新浪新闻数据
- python爬虫抓取多关键词搜索的百度图片
- python爬虫——新浪新闻网络爬虫
- 多线程新浪新闻搜索网络爬虫-基于关键字
- python得爬虫关键词
- python爬虫——根据指定关键词爬取新浪微博
- Python 编写新浪新闻网络爬虫(学习整理)
- 使用python网络爬虫爬取新浪新闻(一)
- python爬虫案例——新浪腾讯股票数据采集
- 【期刊】基于 Python 的新浪微博数据爬虫
- Python核心编程-网络爬虫的分析
- 一个可以用于在百科搜索大量关键词的python爬虫
- 17.6.5 如何用python爬虫百度图片里面可加关键词的搜索结果
- Python网络爬虫(二)-----发送数据
- Python网络数据采集-创建爬虫
- Java中abstract和final、static
- Code Forces 525C Ilya and Sticks
- was mutated while being enumerated
- C++(32)
- UI中简单的猜数字游戏
- 【python网络编程】新浪爬虫:关键词搜索爬取微博数据
- js同一页面iframe调取另一iframe的url
- 进程和线程的差别
- 【干货】Android studio教程与问题汇总
- Java网络编程
- Caffe学习:Layers
- C++(33)模板与泛型之实例化
- Android 5.1 Phone MO(去电)流程分析(Framework层)
- **HDU 4281 - Judges' response(DP`背包+TSP)