logo资料库

Python新浪微博爬虫程序.docx

第1页 / 共13页
第2页 / 共13页
第3页 / 共13页
第4页 / 共13页
第5页 / 共13页
第6页 / 共13页
第7页 / 共13页
第8页 / 共13页
资料共13页,剩余部分请下载后查看
0x00. 起因
0x01. 基础知识
0x02. 开始
0x03. 收集必要信息
0x04. 编码
1.爬取用户微博
2.爬取关键词
0x05. 后记
Python 新浪微博爬虫程序 标签: python 新浪微博爬虫 2015-09-24 01:01 2825 人阅读 评论(0) 收藏 举报 分类: python 版权声明:本文为博主原创文章,未经博主允许不得转载。 写在前面:本文比较详细,不想看啰嗦的可以直接到这里下载源码 0x00. 起因 因为参加学校大学生创新竞赛,研究有关微博博文表达的情绪,需要大 量微博博文,而网上无论是国内的某度、csdn,还是国外谷歌、gayhub、 codeproject 等都找不到想要的程序,没办法只能自己写一个程序了。 ps.在爬盟找到类似的程序,但是是 windows 下的,并且闭源,而且最 终爬取保存的文件用 notepad++打开有很多奇怪的问题,所以放弃了。 0x01. 基础知识 本程序由 Python 写成,所以基本的 Python 知识是必须的。另外,如果 你有一定的计算机网络基础,在前期准备时会有少走很多弯路。 对于爬虫,需要明确几点: 1. 对爬取对象分类,可以分为以下几种:第一种是不需要登录的,比
如博主以前练手时爬的中国天气网,这种网页爬取难度较低,建议爬虫 新手爬这类网页;第二种是需要登录的,如豆瓣、新浪微博,这些网页 爬取难度较高;第三种独立于前两种,你想要的信息一般是动态刷新的, 如 AJAX 或内嵌资源,这种爬虫难度最大,博主也没研究过,在此不细 举(据同学说淘宝的商品评论就属于这类)。 2. 如果同一个数据源有多种形式(比如电脑版、手机版、客户端等), 优先选取较为“纯净的”展现。比如新浪微博,有网页版,也有手机版, 而且手机版可以用电脑浏览器访问,这时我优先选手机版新浪微博。 3. 爬虫一般是将网页下载到本地,再通过某些方式提取出感兴趣的信 息。也就是说,爬取网页只完成了一半,你还要将你感兴趣的信息从下 载下来的 html 文件中提取出来。这时就需要一些 xml 的知识了,在这 个项目中,博主用的是 XPath 提取信息,另外可以使用 XQuery 等等其 他技术,详情请访问 w3cschool。 4. 爬虫应该尽量模仿人类,现在网站反爬机制已经比较发达,从验证 码到禁 IP,爬虫技术和反爬技术可谓不断博弈。 0x02. 开始 决定了爬虫的目标之后,首先应该访问目标网页,明确目标网页属于上 述几种爬虫的哪种,另外,记录为了得到感兴趣的信息你需要进行的步 骤,如是否需要登录,如果需要登录,是否需要验证码;你要进行哪些
操作才能获得希望得到的信息,是否需要提交某些表单;你希望得到的 信息所在页面的 url 有什么规律等等。 以下博文以博主项目为例,该项目爬取特定新浪微博用户从注册至今的 所有微博博文和根据关键词爬取 100 页微博博文(大约 1000 条)。 0x03. 收集必要信息 首先访问目标网页,发现需要登录,进入登录页面如下 注意 url 后半段有很多形如”%xx”的转义字符,本文后面将会讲到。 从这个页面可以看到,登录新浪微博手机版需要填写账号、密码和验证 码。 这个验证码是近期(本文创作于 2016.3.11)才需要提供的,如果不需 要提供验证码的话,将有两种方法进行登录。 第一种是填写账号密码之后执行 js 模拟点击“登录”按钮,博主之前 写过一个 Java 爬虫就是利用这个方法,但是现在找不到工程了,在此 不再赘述。 第二种需要一定 HTTP 基础,提交包含所需信息的 HTTP POST 请求。我 们需要 Wireshark 工具来抓取登录微博时我们发出和接收的数据包。 如下图我抓取了在登录时发出和接收的数据包 在搜索栏提供搜索条件”http”可得到所有 http 协议数据包,右侧
info 显示该数据包的缩略信息。图中蓝色一行是 POST 请求,并且 info 中有”login”,可以初步判断这个请求是登录时发出的第一个数据包, 并且这个 180.149.153.4 应该是新浪微博手机版登录认证的服务器 IP 地址,此时我们并没有任何的 cookie。 在序号为 30 是数据包中有一个从该 IP 发出的 HTTP 数据包,里面有四 个 Set-Cookie 字段,这些 cookie 将是我们爬虫的基础。 早在新浪微博服务器反爬机制升级之前,登录是不需要验证码的,通过 提交 POST 请求,可以拿到这些 cookie,在项目源码中的 TestCookie.py 中有示例代码。 ps.如果没有 wireshark 或者不想这么麻烦的话,可以用浏览器的开发 者工具,以 chrome 为例,在登录前打开开发者工具,转到 Network,登 录,可以看到发出和接收的数据,登录完成后可以看到 cookies,如下 图 接下来访问所需页面,查看页面 url 是否有某种规律。由于本项目目标 之一是获取某用户的全部微博,所以直接访问该用户的微博页面,以央 视新闻 为例。 图为央视新闻微博第一页,观察该页面的 url 可以发现,新浪微博手机 版的微博页面 url 组成
是 “weibo.cn/(displayID)?page=(pagenum)” 。这将成为我们爬 虫拼接 url 的依据。 接下来查看网页源码,找到我们希望得到的信息的位置。打开浏览器开 发者工具,直接定位某条微博,可以发现它的位置,如下所示。 观察 html 代码发现,所有的微博都在
标签里,并且这个标签里有 两个属性,其中 class 属性为”c”,和一个唯一的 id 属性值。得到这 个信息有助于将所需信息提取出来。 另外,还有一些需要特别注意的因素 * 微博分为原创微博和转发微博 * 按照发布时间至当前时间的差距,在页面上有”MM 分钟前”、”今天 HH:MM”、”mm 月 dd 日 HH:MM”、”yyyy-mm-dd HH:MM:SS”等多种显 示时间的方式 * 手机版新浪微博一个页面大约显示 10 条微博,所以要注意对总共页 数进行记录 以上几点都是细节,在爬虫和提取的时候需要仔细考虑。 0x04. 编码 1.爬取用户微博 本项目开发语言是 Python 2.7,项目中用了一些第三方库,第三方库可 以用 pip 的方法添加。
既然程序自动登录的想法被验证码挡住了,想要访问特定用户微博页面, 只能使用者提供 cookies 了。 首先用到的是 Python 的 request 模块,它提供了带 cookies 的 url 请 求。 import request print request.get(url, cookies=cookies).content 使用这段代码就可以打印带 cookies 的 url 请求页面结果。 首先取得该用户微博页面数,通过检查网页源码,查找到表示页数的元 素,通过 XPath 等技术提取出页数。 项目使用 lxml 模块对 html 进行 XPath 提取。 首先导入 lxml 模块,在项目里只用到了 etree,所以 from lxml import etree 然后利用下面的方法返回页数 def getpagenum(self): url = self.geturl(pagenum=1) html = requests.get(url, cookies=self.cook).content # Visit the first page to get the page number. selector = etree.HTML(html) pagenum = selector.xpath('//input[@name="mp"]/@value')[0] return int(pagenum) 接下来就是不断地拼接 url->访问 url->下载网页。 需要注意的是,由于新浪反爬机制的存在,同一 cookies 访问页面过于 “频繁”的话会进入类似于“冷却期”,即返回一个无用页面,通过分
析该无用页面发现,这个页面在特定的地方会出现特定的信息,通过 XPath 技术来检查这个特定地方是否出现了特定信息即可判断该页面是 否对我们有用。 def ispageneeded(html): selector = etree.HTML(html) try: title = selector.xpath('//title')[0] except: return False return title.text != '微博广场' and title.text != '微博' 如果出现了无用页面,只需简单地重新访问即可,但是通过后期的实验 发现,如果长期处于过频访问,返回的页面将全是无用页面,程序也将 陷入死循环。为了避免程序陷入死循环,博主设置了尝试次数阈值 trycount,超过这个阈值之后方法自动返回。 下面代码片展示了单线程爬虫的方法。 def startcrawling(self, startpage=1, trycount=20): attempt = 0 try: os.mkdir(sys.path[0] + '/Weibo_raw/' + self.wanted) except Exception, e: print str(e) isdone = False while not isdone and attempt < trycount: try: pagenum = self.getpagenum() isdone = True except Exception, e: attempt += 1 if attempt == trycount: return False i = startpage while i <= pagenum: attempt = 0 isneeded = False
html = '' while not isneeded and attempt < trycount: html = self.getpage(self.geturl(i)) isneeded = self.ispageneeded(html) if not isneeded: attempt += 1 if attempt == trycount: return False self.savehtml(sys.path[0] + '/Weibo_raw/' + self.wanted + '/' + str(i) + '.txt', html) print str(i) + '/' + str(pagenum - 1) i += 1 return True 考虑到程序的时间效率,在写好单线程爬虫之后,博主也写了多线程爬 虫版本,基本思想是将微博页数除以线程数,如一个微博用户有 100 页 微博,程序开 10 个线程,那么每个线程只负责 10 个页面的爬取,其他 基本思想跟单线程类似,只需仔细处理边界值即可,在此不再赘述,感 兴趣的同学可以直接看代码。另外,由于多线程的效率比较高,并发量 特别大,所以服务器很容易就返回无效页面,此时 trycount 的设置就 显得更重要了。博主在写这篇微博的时候,用一个新的 cookies,多线 程爬取现场测试了一下爬取北京邮电大学的微博,3976 条微博全部爬取 成功并提取博文,用时仅 15s,实际可能跟 cookies 的新旧程度和网络 环境有关,命令行设置如下,命令行意义在项目网址里有说明 python main.py _T_WM=xxx; SUHB=xxx; SUB=xxx; gsid_CTandWM=xxx u bupt m 20 20 爬取的工作以上基本介绍结束,接下来就是爬虫的第二部分,解析了。 由于项目中提供了多线程爬取方法,而多线程一般是无序的,但微博博 文是依靠时间排序的,所以项目采用了一种折衷的办法,将下载完成的
分享到:
收藏