爬取与电话销售有关的微博

因为公司原因,需要写个微博爬虫,爬点数据做个分析来进行研究,哈哈
俗话说:360行,行行出状元
主要是我想看看微博上网友们对 电话销售 这行有什么样的评价
所以有了下面这么一个爬虫

1. 网页URL分析

这里我选择爬取的是移动版微博(https://m.weibo.cn)
首先,进入网站,登录进去。然后在搜索框 搜索"电话销售",然后按一下F12,看网页源码,如下图:
在这里插入图片描述
如上图最右边画红圈的部分
微博是异步获取的,所以我们要找到真正的网页URL,按照上面的步骤,很容易就找到这个URL了

2. 编写爬虫程序

接下来就可以开始爬取了,首先解决微博的登录以及验证码的问题
大家可以参考一下这里
登录及验证码问题我就不多说了,直接看代码吧
这是整个爬虫所需要的导入的库

from bs4 import BeautifulSoup as Bs
import pandas
import re
import json
import time
import base64
import rsa
import binascii
import requests
import random

以下是解决登录和验证的代码
代码有点长,如果各位有更简单的,可以教一下我,哈哈

#如果没有开启登录保护,不用输入验证码就可以登录
#如果开启登录保护,需要输入验证码
try:
    from PIL import Image
except:
    pass
try:
    from urllib.parse import quote_plus
except:
    from urllib import quote_plus


# 构造请求头
act_for = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0'
headers = {
    'User-Agent': act_for
}

session = requests.session()   #设置全局的session,后面把cookie存进session里

# 访问初始网址的页面时带上 cookie
initial_url = "http://weibo.com/login.php"
try:
    session.get(initial_url, headers=headers, timeout=2)
except:
    session.get(initial_url, headers=headers)
try:
    input = rowinput
except:
    pass


def get_su(username):
    #对 email 地址和手机号码 先 javascript 中 encodeURIComponent
    username_quote = quote_plus(username)
    username_base64 = base64.b64encode(username_quote.encode("utf-8"))  #用base64加密
    # 加密后decode成utf8格式并返回
    return username_base64.decode("utf-8")


# 预登陆获得 servertime, nonce, pubkey, rsakv
def get_server_data(su):
    pre_url = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su="
    pre_url = pre_url + su + "&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.18)&_="
    pre_url = pre_url + str(int(time.time() * 1000))
    pre_data_res = session.get(pre_url, headers=headers)

    sever_data = eval(pre_data_res.content.decode("utf-8").replace("sinaSSOController.preloginCallBack", ''))

    return sever_data


def get_password(password, servertime, nonce, pubkey):  #获取密码等加密信息
    rsaPublickey = int(pubkey, 16)
    key = rsa.PublicKey(rsaPublickey, 65537)  # 创建公钥
    message = str(servertime) + '\t' + str(nonce) + '\n' + str(password)  # 拼接明文js加密文件中得到
    message = message.encode("utf-8")
    passwd = rsa.encrypt(message, key)  # 加密
    passwd = binascii.b2a_hex(passwd)  # 将加密信息转换为16进制。
    return passwd


def get_cha(pcid):  #获取验证码并写进图片中
    cha_url = "http://login.sina.com.cn/cgi/pin.php?r="
    cha_url = cha_url + str(int(random.random() * 100000000)) + "&s=0&p="
    cha_url = cha_url + pcid
    cha_page = session.get(cha_url, headers=headers)    #获取到验证码
    with open("cha.jpg", 'wb') as f:
        f.write(cha_page.content)   #写进图片里
        f.close()
    try:
        im = Image.open("cha.jpg")
        im.show()
        im.close()
    except:
        print("请到当前目录下,找到验证码后输入")


def login(username, password):     #做登录并获取cookies的操作
    su = get_su(username)   # su 是加密后的用户名
    sever_data = get_server_data(su)
    servertime = sever_data["servertime"]
    nonce = sever_data['nonce']
    rsakv = sever_data["rsakv"]
    pubkey = sever_data["pubkey"]
    showpin = sever_data["showpin"]
    password_secret = get_password(password, servertime, nonce, pubkey)     #调用上面的获取密码的函数

    postdata = {
        'entry': 'weibo',
        'gateway': '1',
        'from': '',
        'savestate': '7',
        'useticket': '1',
        'pagerefer': "http://login.sina.com.cn/sso/logout.php?entry=miniblog&r=http%3A%2F%2Fweibo.com%2Flogout.php%3Fbackurl",
        'vsnf': '1',
        'su': su,
        'service': 'miniblog',
        'servertime': servertime,
        'nonce': nonce,
        'pwencode': 'rsa2',
        'rsakv': rsakv,
        'sp': password_secret,
        'sr': '1366*768',
        'encoding': 'UTF-8',
        'prelt': '115',
        'url': 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=https%3A%2F%2Fm.weibo.cn%2F',
        'returntype': 'META'
        }
    login_url = 'http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)'
    if showpin == 0:
        login_page = session.post(login_url, data=postdata, headers=headers)
    else:
        pcid = sever_data["pcid"]
        get_cha(pcid)
        postdata['door'] = input('请输入验证码:')    #获取验证码
        login_page = session.post(login_url, data=postdata, headers=headers)    #存到session的post方法里
    login_loop = (login_page.content.decode("GBK"))
    # print(login_loop)
    pa = r'location\.replace\([\'"](.*?)[\'"]\)'
    loop_url = re.findall(pa, login_loop)[0]
    # print(loop_url)

    login_index = session.get(loop_url, headers=headers)
    uuid = login_index.text
    uuid_pa = r'"uniqueid":"(.*?)"'
    uuid_res = re.findall(uuid_pa, uuid, re.S)
    web_weibo_url = "http://weibo.com/%s/profile?topnav=1&wvr=6&is_all=1" % uuid_res
    weibo_page = session.get(web_weibo_url, headers=headers)
    weibo_pa = r'<title>(.*?)</title>'
    # print(weibo_page.content.decode("utf-8"))
    userID = re.findall(weibo_pa, weibo_page.content.decode("utf-8", 'ignore'), re.S)[0]    #把用户ID拿出来
    print('用户:',userID,"微博登陆成功!" )

    cooki=requests.utils.dict_from_cookiejar(session.cookies)   #把cookie字符串化
    with open('cooki.txt','w') as fp:
        json.dump(cooki,fp)     #把cookie存进txt文档中
        fp.close()

2.1 爬取数据

既然解决了登录验证问题,并获取到了cookie,那就直接从cookie中获取源数据就好了
获取到源数据,再从它里面找到我们想要的数据

 #获取网页源代码并用json解析
def create_soup(page):  

    html=session.get(page,timeout=10).text.encode('utf-8')   #从cookie中获取页面源代码
    html=json.loads(html)   #用json解析一遍
    html=html['data']   #拿出需要的部分
    data = html['cards']    #拿出需要的部分
    return  data

值得注意的是,移动版的微博源代码并不是html格式的,而是字典格式,如图:
在这里插入图片描述
you see see,字典格式,获取数据那不就更简单了吗
直接把想要的数据切片出来就好了
也免得用BeautifulSoup去再解析一遍了
那接下来就开始获取数据,先把数据存进DataFrame里面

def personal_info(data):
    # 创建一个空的带字段的DataFrame
    pds_per_data = pandas.DataFrame(columns=['u_id', 'nick_name', 'gender',
                                    'urank', 'tweets_count','follow_count', 'description'])
    for i in range(0, 15):
        try:
            try:
                content = data[i]['mblog']['longText']['longTextContent']
                u_id = data[i]['mblog']['user']['id']
                nick_name = data[i]['mblog']['user']['screen_name']
                gender = data[i]['mblog']['user']['gender']
                urank = data[i]['mblog']['user']['urank']
                tweets_count = data[i]['mblog']['user']['statuses_count']
                follow_count = data[i]['mblog']['user']['follow_count']
                followers_count = data[i]['mblog']['user']['followers_count']
                description = data[i]['mblog']['user']['description']

            except Exception :
                u_id = data[i]['mblog']['user']['id']
                nick_name = data[i]['mblog']['user']['screen_name']
                gender = data[i]['mblog']['user']['gender']
                urank = data[i]['mblog']['user']['urank']
                tweets_count = data[i]['mblog']['user']['statuses_count']
                follow_count = data[i]['mblog']['user']['follow_count']
                followers_count = data[i]['mblog']['user']['followers_count']
                description = data[i]['mblog']['user']['description']

            # 把数据按不同字段添加进DataFrame里面
            column = {'u_id': u_id, 'nick_name': nick_name, 'gender': gender, 'urank': urank,
                      'tweets_count': tweets_count, 'follow_count': follow_count,
                      'followers_count': followers_count, 'description': description}
            pds_per_data = pds_per_data.append([column], ignore_index=True, sort=True)
        except Exception :
            pass
        time.sleep(0.001)

    return pds_per_data



def tweets_info(data):
    #创建一个空的带字段的DataFrame
    pds_tws_data = pandas.DataFrame(columns=['m_id', 'u_id', 'locality',
                                             'content', 'tools', 'pub_time',
                                             'faward_num','comment_num','like_num'])
    for j in range(0, 15):
        try:
            try:
                m_id = data[j]['mblog']['mid']
                u_id = data[j]['mblog']['user']['id']
                locality = data[j]['mblog']['longText']['url_objects'][0]['object']['object']['address']['region']
                content = data[j]['mblog']['longText']['longTextContent']
                tools = data[j]['mblog']['source']
                pub_time = data[j]['mblog']['created_at']
                faward_num = data[j]['mblog']['user']['statuses_count']
                comment_num = data[j]['mblog']['comments_count']
                like_num = data[j]['mblog']['attitudes_count']

            except Exception:
                m_id = data[j]['mblog']['mid']
                u_id = data[j]['mblog']['user']['id']
                locality = ''
                content = data[j]['mblog']['text']
                tools = data[j]['mblog']['source']
                pub_time = data[j]['mblog']['created_at']
                faward_num = data[j]['mblog']['user']['statuses_count']
                comment_num = data[j]['mblog']['comments_count']
                like_num = data[j]['mblog']['attitudes_count']

            #把数据按不同字段添加进DataFrame里面
            col = {'m_id': m_id, 'u_id': u_id, 'locality': locality, 'content': content,
                      'tools': tools, 'pub_time': pub_time,'faward_num': faward_num,
                      'comment_num': comment_num, 'like_num': like_num}
            pds_tws_data = pds_tws_data.append([col], ignore_index=True, sort=True)
        except Exception:
            pass
        time.sleep(0.001)

    return pds_tws_data

you see see,you see see,这样就得到 “Personal_data” 和 “Tweets_data” 两张表的数据了
最后,在主函数里实现翻页爬取的操作就好了

if __name__ == '__main__':
    username = 'XXXXX@163.com'		#账号
    password = 'XXXXXXXXXXX'			#密码
    login(username, password)      #微博登陆
    coki_open=open('cooki.txt').read()  #读取cooki文档
    cks=json.loads(coki_open)   #用json解析一遍
    session.cookies = requests.utils.cookiejar_from_dict(cks)   #把字符类型的cookie转成字典并存进session里面

    url = 'https://m.weibo.cn/api/container/getIndex?containerid=' \
          '100103type%3D1%26q%3D%E7%94%B5%E8%AF%9D%E9%94%80%E5%94%AE&page_type=searchall&page={}'  # 我们要爬取的微博网址
    Psn_Data = pandas.DataFrame()
    Tws_Data = pandas.DataFrame()
    #进行翻页爬取
    for k in range(1,100000):
        try:
            page = url.format(k)    #赋值进url里面
            pds_per_data = personal_info(create_soup(page))     #调用函数
            Psn_Data = Psn_Data.append(pds_per_data,sort=False)     #把爬取到的数据添加进DataFrame里面

            pds_tws_data = tweets_info(create_soup(page))
            Tws_Data = Tws_Data.append(pds_tws_data,sort=False)
            print('已爬取{}页'.format(k))
        except Exception :
            pass
        time.sleep(0.001)   #暂停0.001秒再进行爬取

    #Psn_Data表
    Psn_Data=Psn_Data.drop_duplicates('u_id')       #按u_id字段去重
    Psn_Data.to_csv('m_weibo_data/Personal_data.csv')   #写进CSV文档里
    Psn_Data.drop(index=Psn_Data.index, inplace=True)   #按如果有重复的就替换掉

    #Tws_Data表
    Tws_Data = Tws_Data.drop_duplicates('m_id')
    Tws_Data.to_csv('m_weibo_data/Tweets_data.csv')
    Tws_Data.drop(index=Tws_Data.index, inplace=True)

3. 数据信息

爬虫程序一共爬取了两个表的数据
分别是 个人信息表(Personal_data)

**Personal_data 表:**
u_id:微博ID
nick_name:微博昵称
description:个性签名
gender:性别
urank:微博等级
follow_count:关注的数量
followers_count:粉丝数量
tweets_count:已发微博的数量

在这里插入图片描述
还有博文信息表(Tweets_data)

**Tweets_data 表:**
m_id:微博ID
locality:所在地区
pub_time:发微博的时间
tools:发微博所用的工具
u_id:用户ID
content:微博内容
faward_num:转发数量
comment_num:评论数量
like_num:点赞数量

在这里插入图片描述

4. 总结

以上就是爬虫程序的全过程了,其实这个爬虫还是有点问题的
爬虫虽然写好了,但是这两天在忙别的事情,先这样吧
下次把爬虫完善一下,一起补上来~

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值