【爬虫初探】新浪微博搜索爬虫实现

全文概述

功能:爬取新浪微博的搜索结果,支持高级搜索中对搜索时间的限定

网址http://s.weibo.com/

实现:采取selenium测试工具,模拟微博登录,结合PhantomJS/Firefox,分析DOM节点后,采用Xpath对节点信息进行获取,实现重要信息的抓取,并存储至Excel中。

获取的微博信息包括:博主昵称, 博主主页, 微博认证, 微博达人, 微博内容, 发布时间, 微博地址, 微博来源, 转发, 评论, 赞

代码请详见Github:weibo_search_spider

实现

一、微博登陆

一般的微博模拟登陆向服务器传送cookies,但是selenium可以通过模拟点击实现登陆,登陆时需要输入验证码。通过登陆新浪通行证(http://login.sina.com.cn/),便可以以登陆的身份打开微博。

driver = webdriver.Firefox()

def LoginWeibo(username, password):
    try:
        #输入用户名/密码登录
        print u‘准备登陆Weibo.cn网站...‘
        driver.get("http://login.sina.com.cn/")
        elem_user = driver.find_element_by_name("username")
        elem_user.send_keys(username) #用户名
        elem_pwd = driver.find_element_by_name("password")
        elem_pwd.send_keys(password)  #密码
        elem_sub = driver.find_element_by_xpath("//input[@class=‘smb_btn‘]")
        elem_sub.click()              #点击登陆 因无name属性

        try:
            #输入验证码
            time.sleep(10)
            elem_sub.click()
        except:
            #不用输入验证码
            pass

        print ‘Crawl in ‘, driver.current_url
        print u‘输出Cookie键值对信息:‘
        for cookie in driver.get_cookies():
            print cookie
            for key in cookie:
                print key, cookie[key]
        print u‘登陆成功...‘
    except Exception,e:
        print "Error: ",e
    finally:
        print u‘End LoginWeibo!\n‘

注意:Firefox登陆时是否需要输入验证码在不同机器上表现不一,譬如在我电脑上无需输入验证码即可登录而在另一台服务器上需要输入验证码。所以如果需要输入验证码, 则只能通过Firefox实现,因为PhantomJS作为headless浏览器,无法实现输入验证码的功能。

二、搜索并处理结果

访问http://s.weibo.com/页面,输入关键词,点击搜索后,限定搜索的时间范围,处理页面的搜索结果。

总体调度

搜索的总调度程序如下:

def GetSearchContent(key):

    driver.get("http://s.weibo.com/")
    print ‘搜索热点主题:‘, key.decode(‘utf-8‘)

    #输入关键词并点击搜索
    item_inp = driver.find_element_by_xpath("//input[@class=‘searchInp_form‘]")
    item_inp.send_keys(key.decode(‘utf-8‘))
    item_inp.send_keys(Keys.RETURN)    #采用点击回车直接搜索

    #获取搜索词的URL,用于后期按时间查询的URL拼接
    current_url = driver.current_url
    current_url = current_url.split(‘&‘)[0] #http://s.weibo.com/weibo/%25E7%258E%2589%25E6%25A0%2591%25E5%259C%25B0%25E9%259C%2587

    global start_stamp
    global page

    #需要抓取的开始和结束日期
    start_date = datetime.datetime(2010,4,13,0)
    end_date = datetime.datetime(2010,4,26,0)
    delta_date = datetime.timedelta(days=1)

    #每次抓取一天的数据
    start_stamp = start_date
    end_stamp = start_date + delta_date

    global outfile
    global sheet

    outfile = xlwt.Workbook(encoding = ‘utf-8‘)

    while end_stamp <= end_date:

        page = 1

        #每一天使用一个sheet存储数据
        sheet = outfile.add_sheet(str(start_stamp.strftime("%Y-%m-%d-%H")))
        initXLS()

        #通过构建URL实现每一天的查询
        url = current_url + ‘&typeall=1&suball=1&timescope=custom:‘ + str(start_stamp.strftime("%Y-%m-%d-%H")) + ‘:‘ + str(end_stamp.strftime("%Y-%m-%d-%H")) + ‘&Refer=g‘
        driver.get(url)

        handlePage()  #处理当前页面内容

        start_stamp = end_stamp
        end_stamp = end_stamp + delta_date

构造搜索时间

在搜索时间的构造方面,实际上有高级搜索-搜索时间选择按钮可以进行搜索时间的选择。但是对所有的行为进行selenium点击模拟似乎有些太过复杂,而且在实现的过程中发现由于两个日期的选择公用一个calendar,不知是何原因导致截至日期选择时会出错。

所以上面介绍了一种更加简便的方法:构造datetime对象并加入URL。

通过对限定时间的搜索URL进行分析可以看出,只需要在基本URL基础上加入时间的限定即可。

http://s.weibo.com/weibo/%25E7%258E%2589%25E6%25A0%2591%25E5%259C%25B0%25E9%259C%2587&typeall=1&suball=1&timescope=custom:2016-05-01-0:2016-05-02-0&Refer=g

单个页面数据处理

每一个页面加载完毕之后,需要经过一系列判断,最终决定是否有内容可以获取

#页面加载完成后,对页面内容进行处理
def handlePage():
    while True:
        #之前认为可能需要sleep等待页面加载,后来发现程序执行会等待页面加载完毕
        #sleep的作用是对付微博的反爬虫机制,抓取太快可能会判定为机器人,需要输入验证码
        time.sleep(2)
        #先行判定是否有内容
        if checkContent():
            print "getContent"
            getContent()
            #先行判定是否有下一页按钮
            if checkNext():
                #拿到下一页按钮
                next_page_btn = driver.find_element_by_xpath("//a[@class=‘page next S_txt1 S_line1‘]")
                next_page_btn.click()
            else:
                print "no Next"
                break
        else:
            print "no Content"
            break

页面加载结果判断

在这里,点击搜索按钮之后的搜索结果可能有以下几种情况

1、页面无搜索结果

如图中所示,如果在指定时间内,关键词无搜索结果(此时,页面中会有推荐微博,推荐微博很容易被当作是正常微博)。通过与有搜索结果的页面比较,此类页面最典型的特征是拥有"class = pl_noresult"的div,可以通过Xpath查找"//div[@class=‘pl_noresult‘]"的节点是否存在来判定有搜索结果,具体判定如下:

#判断页面加载完成后是否有内容
def checkContent():
    #有内容的前提是有“导航条”?错!只有一页内容的也没有导航条
    #但没有内容的前提是有“pl_noresult”
    try:
        driver.find_element_by_xpath("//div[@class=‘pl_noresult‘]")
        flag = False
    except:
        flag = True
    return flag

2、页面有搜索结果,且只有一页

通过仔细分析,这样的页面最典型的特征是没有导航条,即没有“下一页”按钮

3、页面有搜索结果,且有不止一页

类似这样的情况,最典型的特征是有“下一页”按钮,那么2和3判断的标准就可以是是否有“下一页”按钮。如果有,就可以点击进入下一页啦!

#判断是否有下一页按钮
def checkNext():
    try:
        driver.find_element_by_xpath("//a[@class=‘page next S_txt1 S_line1‘]")
        flag = True
    except:
        flag = False
    return flag

获取页面内容

在判定页面有内容的前提下,页面内容的获取是最重要的一部分,通过分析页面DOM节点,逐一获取需要的信息:

#在页面有内容的前提下,获取内容
def getContent():

    #寻找到每一条微博的class
    nodes = driver.find_elements_by_xpath("//div[@class=‘WB_cardwrap S_bg2 clearfix‘]")

    #在运行过程中微博数==0的情况,可能是微博反爬机制,需要输入验证码
    if len(nodes) == 0:
        raw_input("请在微博页面输入验证码!")
        url = driver.current_url
        driver.get(url)
        getContent()
        return

    dic = {}

    global page
    print str(start_stamp.strftime("%Y-%m-%d-%H"))
    print u‘页数:‘, page
    page = page + 1
    print u‘微博数量‘, len(nodes)

    for i in range(len(nodes)):
        dic[i] = []

        try:
            BZNC = nodes[i].find_element_by_xpath(".//div[@class=‘feed_content wbcon‘]/a[@class=‘W_texta W_fb‘]").text
        except:
            BZNC = ‘‘
        print u‘博主昵称:‘, BZNC
        dic[i].append(BZNC)

        try:
            BZZY = nodes[i].find_element_by_xpath(".//div[@class=‘feed_content wbcon‘]/a[@class=‘W_texta W_fb‘]").get_attribute("href")
        except:
            BZZY = ‘‘
        print u‘博主主页:‘, BZZY
        dic[i].append(BZZY)

        try:
            WBRZ = nodes[i].find_element_by_xpath(".//div[@class=‘feed_content wbcon‘]/a[@class=‘approve_co‘]").get_attribute(‘title‘)#若没有认证则不存在节点
        except:
            WBRZ = ‘‘
        print ‘微博认证:‘, WBRZ
        dic[i].append(WBRZ)

        try:
            WBDR = nodes[i].find_element_by_xpath(".//div[@class=‘feed_content wbcon‘]/a[@class=‘ico_club‘]").get_attribute(‘title‘)#若非达人则不存在节点
        except:
            WBDR = ‘‘
        print ‘微博达人:‘, WBDR
        dic[i].append(WBDR)

        try:
            WBNR = nodes[i].find_element_by_xpath(".//div[@class=‘feed_content wbcon‘]/p[@class=‘comment_txt‘]").text
        except:
            WBNR = ‘‘
        print ‘微博内容:‘, WBNR
        dic[i].append(WBNR)

        try:
            FBSJ = nodes[i].find_element_by_xpath(".//div[@class=‘feed_from W_textb‘]/a[@class=‘W_textb‘]").text
        except:
            FBSJ = ‘‘
        print u‘发布时间:‘, FBSJ
        dic[i].append(FBSJ)

        try:
            WBDZ = nodes[i].find_element_by_xpath(".//div[@class=‘feed_from W_textb‘]/a[@class=‘W_textb‘]").get_attribute("href")
        except:
            WBDZ = ‘‘
        print ‘微博地址:‘, WBDZ
        dic[i].append(WBDZ)

        try:
            WBLY = nodes[i].find_element_by_xpath(".//div[@class=‘feed_from W_textb‘]/a[@rel]").text
        except:
            WBLY = ‘‘
        print ‘微博来源:‘, WBLY
        dic[i].append(WBLY)

        try:
            ZF_TEXT = nodes[i].find_element_by_xpath(".//a[@action-type=‘feed_list_forward‘]//em").text
            if ZF_TEXT == ‘‘:
                ZF = 0
            else:
                ZF = int(ZF_TEXT)
        except:
            ZF = 0
        print ‘转发:‘, ZF
        dic[i].append(str(ZF))

        try:
            PL_TEXT = nodes[i].find_element_by_xpath(".//a[@action-type=‘feed_list_comment‘]//em").text#可能没有em元素
            if PL_TEXT == ‘‘:
                PL = 0
            else:
                PL = int(PL_TEXT)
        except:
            PL = 0
        print ‘评论:‘, PL
        dic[i].append(str(PL))

        try:
            ZAN_TEXT = nodes[i].find_element_by_xpath(".//a[@action-type=‘feed_list_like‘]//em").text #可为空
            if ZAN_TEXT == ‘‘:
                ZAN = 0
            else:
                ZAN = int(ZAN_TEXT)
        except:
            ZAN = 0
        print ‘赞:‘, ZAN
        dic[i].append(str(ZAN))

        print ‘\n‘

    #写入Excel
    writeXLS(dic)

写在最后

上一篇博客中我提到过:一般来说,数据抓取工作主要有两种方式:一是通过抓包工具(Fiddle)进行抓包分析,获取ajax请求的URL,通过URL抓取数据,这也是更为通用、推荐的方法;另外一种方法就是后面要使用的模拟浏览器行为的爬虫。

我深知,本文所使用的数据抓取方法是一种效率较为低下的方式,但另外一方面来看,也是入门较快的一种方式,只需要掌握selenium、xpath的基础语法,便可以快速地构建爬虫程序。接下来会更加深入地研究高效率的爬虫方法。

希望这种简单的思想和方法能够帮助到你,也欢迎多多交流多多指教。

感谢Eastmount九茶的帮助

(By MrHammer 2016-05-02 下午6点 @Bin House Rainy)

时间: 2024-10-11 23:27:28

【爬虫初探】新浪微博搜索爬虫实现的相关文章

Node.js 爬虫初探

前言 在学习慕课网视频和Cnode新手入门接触到爬虫,说是爬虫初探,其实并没有用到爬虫相关第三方类库,主要用了node.js基础模块http.网页分析工具cherrio. 使用http直接获取url路径对应网页资源,然后使用cherrio分析. 这里我主要是把慕课网教学视频提供的案例自己敲了一边,加深理解.在coding的过程中,我第一次把jq获取后的对象直接用forEach遍历,直接报错,是因为jq没有对应的这个方法,只有js数组可以调用. 知识点 ①:superagent抓去网页工具.我暂时

Python3中级玩家:淘宝天猫商品搜索爬虫自动化工具(第一篇)

Python3中级玩家:淘宝天猫商品搜索爬虫自动化工具(第一篇) 一.前言 大家好,今天我要来讲讲一个比较实用的爬虫工具,抓取淘宝的关键字商品信息,即是: 输入关键字,按照价格等排序,抓取列出的商品信息以及下载图片,并且支持导出为Excel. 如果如下: 看完下面的讲解,Python语言就掌握得差不多,中级水平了,而且这个封装后的工具还是很好用的. 感觉自己萌萌哒~~ 二.原理 大家知道什么叫爬虫,它也叫网络蜘蛛,机器人等,意思就是说自动的程序,可以去抓取使用网络协议传输的内容. 目前来讲爬虫主

Ruby用百度搜索爬虫

Ruby用百度搜索爬虫 博主ruby学得断断续续,打算写一个有点用的小程序娱乐一下,打算用ruby通过百度通道爬取网络信息. 第三方库准备 mechanize:比较方便地处理网络请求,类似于Python中的requests nokogiri:解析HTML文本,采用的是jquery选择器 步骤分析 用mechanize创建一个agent对象 我们首先登录百度主页 找到百度『搜索』框的表单 填写表单内容 提交表单(agent用该表单的内容发出submit动作) 分析百度获得的搜索结果列表 用noko

爬虫_83款 网络爬虫开源软件

1.http://www.oschina.net/project/tag/64/spider?lang=0&os=0&sort=view& 搜索引擎 Nutch Nutch 是一个开源Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. 尽管Web搜索是漫游Internet的基本要求, 但是现有web搜索引擎的数目却在下降. 并且这很有可能进一步演变成为一个公司垄断了几乎所有的web... 更多Nutch信息 最近更新:[每日一博]Nu

Python爬虫入门之一通用爬虫和聚焦爬虫

前言 为什么要做爬虫? 首先请问:都说现在是"大数据时代",那数据从何而来? 企业产生的用户数据:百度指数.阿里指数.TBI腾讯浏览指数.新浪微博指数 数据平台购买数据:数据堂.国云数据市场.贵阳大数据交易所 政府/机构公开的数据:中华人民共和国国家统计局数据.世界银行公开数据.联合国数据.纳斯达克 数据管理咨询公司:麦肯锡.埃森哲.艾瑞咨询 爬取网络数据:如果需要的数据市场上没有,或者不愿意购买,那么可以选择招/做一名爬虫工程师,自己动手丰衣足食. 爬虫是什么? 网络爬虫是一种按照一

转 Python爬虫入门二之爬虫基础了解

静觅 » Python爬虫入门二之爬虫基础了解 2.浏览网页的过程 在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.baidu.com/ ,我们会看到几张的图片以及百度搜索框,这个过程其实就是用户输入网址之后,经过DNS服务器,找到服务器主机,向服务器发出一个请求,服务器经过解析之后,发送给用户的浏览器 HTML.JS.CSS 等文件,浏览器解析出来,用户便可以看到形形色色的图片了. 因此,用户看到的网页实质是由 HTML 代码构成的,爬虫爬来的便是这些内容

Python爬虫入门二之爬虫基础了解

1.什么是爬虫 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.想抓取什么?这个由你来控制它咯. 比如它在抓取一个网页,在这个网中他发现了一条道路,其实就是指向网页的超链接,那么它就可以爬到另一张网上来获取数据.这样,整个连在一起的大网对这之蜘蛛来说触手可及,分分钟爬下来不是事儿. 2.浏览网页的过程 在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.bai

爬虫学习 Python网络爬虫第三弹《爬取get请求的页面数据》

爬虫学习 Python网络爬虫第三弹<爬取get请求的页面数据> 一.urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用就是可以通过代码模拟浏览器发送请求.其常被用到的子模块在Python3中的为urllib.request和urllib.parse,在Python2中是urllib和urllib2. 二.由易到难的爬虫程序: 1.爬取百度首页面所有数据值 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 #导包 4

Python爬虫进阶一之爬虫框架概述

综述 爬虫入门之后,我们有两条路可以走. 一个是继续深入学习,以及关于设计模式的一些知识,强化Python相关知识,自己动手造轮子,继续为自己的爬虫增加分布式,多线程等功能扩展.另一条路便是学习一些优秀的框架,先把这些框架用熟,可以确保能够应付一些基本的爬虫任务,也就是所谓的解决温饱问题,然后再深入学习它的源码等知识,进一步强化. 就个人而言,前一种方法其实就是自己动手造轮子,前人其实已经有了一些比较好的框架,可以直接拿来用,但是为了自己能够研究得更加深入和对爬虫有更全面的了解,自己动手去多做.