python爬虫批量抓取新浪微博用户ID及用户信息、微博内容

老师给的任务,要对批量的微博文本进行舆情分析。第一步就是数据的抓取。在网上搜了一下大多是基于手机版网页(wap/cn)的爬虫,但是我在电脑上打不开这些网站。
由于自己也是网页小白,所以就参考着别人的代码,硬着头皮直接抓取www.weibo.com的内容了,用的都是很笨的方法,适合入门。

参考链接:
[python爬虫] Selenium爬取新浪微博内容及用户信息
pyhton微博爬虫(2)——获取微博用户关注列表

首先是参考了第一篇文献,通过指定的ID获取微博信息,主要工作是根据电脑版网页修改了网页元素。

由于需要自己输入用户ID,所以能抓取的信息其实很有限,所以就在考虑能否通过一个用户的关注或者粉丝列表,把他们的ID也作为这个程序的输入,再从这些用户的关注、粉丝列表往外扩展,有点类似病毒的扩散,这样就能抓取到客观的用户ID量了。这个涉及到对json数据的识别,以及正则文本的提取。参考了第二篇文献。

具体代码都放在下面了,分为两个py。还有一个问题想优化但是觉得有点难度,就是想把大V和僵尸号、水军剔除掉,只提取普通用户的信息。希望有哥哥姐姐指导一下思路。

python爬虫批量抓取新浪微博用户ID及用户信息、微博内容_第1张图片
python爬虫批量抓取新浪微博用户ID及用户信息、微博内容_第2张图片

代码

# coding=utf-8
# sinascr.py 输入指定用户ID,爬取这些用户的微博信息和内容
"""  
Created on 2018-3-29 @author: goaza123

功能: 爬取新浪微博用户的信息
信息:用户ID 用户名 粉丝数 关注数 微博数 微博内容
网址:http://weibo.com/, http://weibo.cn/无法访问

"""

import time
import re
import os
import sys
import codecs
import shutil
import urllib
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 先调用无界面浏览器PhantomJS或Firefox
# driver = webdriver.PhantomJS(executable_path="G:\phantomjs-1.9.1-windows\phantomjs.exe")
driver = webdriver.Firefox()
wait = ui.WebDriverWait(driver, 10)

# 全局变量 文件操作读写信息
inforead = codecs.open("SinaWeibo_List.txt", 'r', 'utf-8')
infofile = codecs.open("SinaWeibo_Info.txt", 'a', 'utf-8')


# ********************************************************************************
#                  第一步: 登陆weibo.cn 获取新浪微博的cookie
#        该方法针对weibo.cn有效(明文形式传输数据) weibo.com见学弟设置POST和Header方法
#                LoginWeibo(username, password) 参数用户名 密码
#                             验证码暂停时间手动输入
# ********************************************************************************

def LoginWeibo(username, password):
    try:
        # **********************************************************************
        # 直接访问driver.get("http://weibo.cn/5824697471")会跳转到登陆页面 用户id
        #
        # 用户名
        # 密码 "password_4903" 中数字会变动,故采用绝对路径方法,否则不能定位到元素
        #
        # 勾选记住登录状态check默认是保留 故注释掉该代码 不保留Cookie 则'expiry'=None
        # **********************************************************************

        # 输入用户名/密码登录
        print u'准备登陆Weibo.cn网站...'
        driver.get("https://weibo.com/")
        time.sleep(10)   #等待页面载入
        elem_user = driver.find_element_by_id('loginname')
        elem_user.clear()
        elem_user.send_keys(username)  # 用户名
        elem_pwd = driver.find_element_by_class_name('password').find_element_by_name('password')
        elem_pwd.clear()
        elem_pwd.send_keys(password)  # 密码
        # elem_rem = driver.find_element_by_id("login_form_savestate")
        # elem_rem.click()             #记住登录状态

        elem_sub = driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a/span')
        elem_sub.click()  # 点击登陆
        time.sleep(10)    # 重点: 暂停时间输入验证码
        elem_sub.click()  # 点击登陆

        # 获取Coockie 推荐 http://www.cnblogs.com/fnng/p/3269450.html
        #print driver.current_url
        #print driver.get_cookies()  # 获得cookie信息 dict存储
        #print u'输出Cookie键值对信息:'
        for cookie in driver.get_cookies():
            # print cookie
            for key in cookie:
                print key, cookie[key]

        # driver.get_cookies()类型list 仅包含一个元素cookie类型dict
        print u'登陆成功...'
        time.sleep(5)


    except Exception, e:
        print "Error: ", e


# ********************************************************************************
#                  第二步: 访问个人页面http://weibo.cn/302579176并获取信息
#                                VisitPersonPage()
#        编码常见错误 UnicodeEncodeError: 'ascii' codec can't encode characters 
# ********************************************************************************

def VisitPersonPage(user_id):
    try:
        global infofile
        print u'准备访问个人网站.....'
        # 原创内容 http://weibo.cn/guangxianliuyan?filter=1&page=2
        driver.get("http://weibo.com/" + user_id +"?profile_ftype=1&is_all=1#_0")

        # **************************************************************************
        # No.1 直接获取 用户昵称 微博数 关注数 粉丝数
        #      str_name.text是unicode编码类型
        # **************************************************************************

        # 用户id
        print u'个人详细信息'
        print '**********************************************'
        print u'用户id: ' + user_id

        # 昵称
        str_name = driver.find_element_by_xpath("//div[@class='pf_username']")
        str_t = str_name.text.split(" ")
        num_name = str_t[0]  # 空格分隔 获取第一个值 "Eastmount 详细资料 设置 新手区"
        print u'昵称: ' + num_name

        str_intro = driver.find_element_by_xpath("//div[@class='pf_intro']")
        str_t = str_intro.text.split(" ")
        num_intro = str_t[0]  # 空格分隔 获取第一个值 "Eastmount 详细资料 设置 新手区"
        print u'简介: ' + num_intro

        # Error:  'unicode' object is not callable
        # 一般是把字符串当做函数使用了 str定义成字符串 而str()函数再次使用时报错
        try:
            str_wb = driver.find_element_by_xpath("//td[1]/a[@class='t_link S_txt1']/strong")
        except:
            str_wb = driver.find_element_by_xpath("//td[@class='S_line1'][1]/strong")
        pattern = r"\d+\.?\d*"  # 正则提取"微博[0]" 但r"(\[.*?\])"总含[]
        guid = re.findall(pattern, str_wb.text, re.S | re.M)
        for value in guid:
            num_wb = int(value)
            break
        print u'关注数: ' + str(num_wb)

        # 关注数
        try:
            str_gz = driver.find_element_by_xpath("//td[2]/a[@class='t_link S_txt1']/strong")
        except:
            str_gz = driver.find_element_by_xpath("//td[@class='S_line1'][2]/strong")
        guid = re.findall(pattern, str_gz.text, re.M)
        num_gz = int(guid[0])
        print u'粉丝数: ' + str(num_gz)

        # 粉丝数
        try:
            str_fs = driver.find_element_by_xpath("//td[3]/a[@class='t_link S_txt1']/strong")
        except:
            str_fs = driver.find_element_by_xpath("//td[@class='S_line1'][3]/strong")
        guid = re.findall(pattern, str_fs.text, re.M)
        num_fs = int(guid[0])
        print u'微博数: ' + str(num_fs)

        # ***************************************************************************
        # No.2 文件操作写入信息
        # ***************************************************************************

        infofile.write('=====================================================================\r\n')
        infofile.write(u'用户: ' + user_id + '\r\n')
        infofile.write(u'昵称: ' + num_name + '\r\n')
        infofile.write(u'简介: ' + num_intro + '\r\n')
        infofile.write(u'微博数: ' + str(num_wb) + '\r\n')
        infofile.write(u'关注数: ' + str(num_gz) + '\r\n')
        infofile.write(u'粉丝数: ' + str(num_fs) + '\r\n')
        infofile.write(u'微博内容: ' + '\r\n')

        # ***************************************************************************
        # No.3 获取微博内容
        # http://weibo.cn/guangxianliuyan?filter=0&page=1
        # 其中filter=0表示全部 =1表示原创
        # ***************************************************************************

        print '\n'
        print u'获取微博内容信息'
        num = 1
        while num <= 5:
            url_wb = "http://weibo.com/" + user_id + "?filter=0&page=" + str(num)+"&is_all=1" #0所有微博 1原创微博
            print url_wb
            driver.get(url_wb)
            for i in range(15):
                info= driver.find_elements_by_xpath("//div[@class='WB_feed WB_feed_v3 WB_feed_v4']/div["+str(i+2)+"]//div[@class='WB_text W_f14']")
                for value in info:
                    info = value.text
                    print info
                    if info.startswith(u'转发',0,len(info)) or info.startswith(u'//',0,len(info)):
                        print u'转发微博'
                        infofile.write(u'[转发微博]\r\n'+info+'\r\n')
                    else:
                        print u'原创微博'
                        infofile.write(u'[原创微博]\r\n'+info+'\r\n')


            print u'next page...\n'
            infofile.write('\r\n\r\n')
            num += 1
            print '\n\n'
        print '**********************************************'


    except Exception, e:
        print "Error: ", e
    finally:
        print u'VisitPersonPage!\n\n'
        print '**********************************************\n'


# *******************************************************************************
#                                程序入口 预先调用
# *******************************************************************************

if __name__ == '__main__':

    # 定义变量
    username = '******'  # 输入你的微博用户名
    password = '******'  # 输入你的密码
    user_id = 'guangxianliuyan'  # 用户id url+id访问个人

    # 操作函数
    LoginWeibo(username, password)  # 登陆微博


    # driver.add_cookie({'name':'name', 'value':'_T_WM'})
    # driver.add_cookie({'name':'value', 'value':'c86fbdcd26505c256a1504b9273df8ba'})

    # 注意
    # 因为sina微博增加了验证码,但是你用Firefox登陆一次输入验证码,再调用该程序即可,因为Cookies已经保证
    # 会直接跳转到明星微博那部分,即: http://weibo.cn/guangxianliuyan

    # 在if __name__ == '__main__':引用全局变量不需要定义 global inforead 省略即可
    print 'Read file:'
    user_id = inforead.readline()
    while user_id != "":
        user_id = user_id.rstrip('\r\n')
        VisitPersonPage(user_id)  # 访问个人页面
        user_id = inforead.readline()
        # break

    infofile.close()
    inforead.close()

# -*- coding: utf-8 -*-
"""
Created on Thu Aug  3 20:59:53 2017
#sinacra_ID.py
@author: goaza123
"""
import sys
import requests
import json
import time
import random
import re
import codecs
import pymysql.cursors

reload(sys)
sys.setdefaultencoding('utf8')
infofile = codecs.open("SinaWeibo_List.txt", 'a', 'utf-8')

def crawlDetailPage(url,page):
    global ID_get
    global num
    global infofile
    #读取微博网页的JSON信息
    req = requests.get(url)
    jsondata = req.text
    data = json.loads(jsondata)
    #获取每一条页的数据
    content = data['data']['cards']
    #循环输出每一页的关注者各项信息
    for i in content:
        followingId = i['user']['id']
        ID_get.append(followingId)
        num=num+1
        infofile.write(str(followingId)+ '\r\n')

def get_user_info(user_id):   #containerid和usid不一致,查看用户的关注列表需要他的containerid,usid用于获取用户主页信息
    url = 'http://m.weibo.cn/api/container/getIndex?type=uid&value={user_id}'.format(user_id=user_id)
    resp = requests.get(url)
    jsondata = resp.json()
    jsondata = jsondata['data']
    fans_id=jsondata.get('follow_scheme')
    items = re.findall(r"&lfid=(\w+)*", fans_id, re.M)
    for i in items:
         i=i.decode(encoding='UTF-8',errors='strict')
    return i

user_oid=1005051654024040      #这个是我自己的微博containerid,在个人主页点我的微博得到的链接里的数字,也可以换成你自己的
#containerid,https://weibo.com/p/1005051654024040/home?from=page_100505_profile&wvr=6&mod=data#place
#userid,https://weibo.com/1654024040/profile?topnav=1&wvr=6
for cir in range(1,20):
    print("正在获取第{}位用户的粉丝信息:".format(cir))
    num = 0;
    ID_get = [];
    for i in range(1, 3):
        print("正在获取第{}页的粉丝列表:".format(i))
        # 微博用户关注列表JSON链接
        url = "https://m.weibo.cn/api/container/getSecond?containerid={user_oid}_-_FANS&page={page}".format(user_oid=user_oid, page=i)  # page=" +   #FOLOWERS关注,FANS粉丝
        crawlDetailPage(url, i)
        # 设置休眠时间
        t = random.randint(1, 5)
        print("休眠时间为:{}s".format(t))
        time.sleep(t)
    user_id = ID_get[1]
    user_oid = get_user_info(str(user_id))

你可能感兴趣的:(python爬虫批量抓取新浪微博用户ID及用户信息、微博内容)