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

news/2024/7/19 10:21:34 标签: 微博爬虫, 数据分析, 爬虫, 销售, 销售数据

因为公司原因,需要写个爬虫>微博爬虫,爬点数据做个分析来进行研究,哈哈
俗话说: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. 总结

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


http://www.niftyadmin.cn/n/1481813.html

相关文章

android 数值输入限制_Android 限制EditText仅仅能输入数字、限制输入类型、限制输入长度的小技巧...

准确的说让Edittext仅仅能输入数字有方法两种&#xff0c;都是通过xml属性设置方法一&#xff1a;android:id"id/u_account"android:layout_width"0dp"android:layout_height"match_parent"android:layout_marginLeft"13dp"android:in…

[node.js] npm, mqtt, mosca

2019独角兽企业重金招聘Python工程师标准>>> "npm install module --save" not work npm install *module* --save 没有生成 package.json 文件&#xff1f; 需要在项目目录初始化 npm init 后使用 如果已经安装了一些 module&#xff0c;可以使用 npm in…

完美解决浏览器主页被hao123劫持,打开浏览器时自动进入hao123主页怎么办

完美解决浏览器主页被hao123劫持首先使用排除法&#xff1a; 第一步&#xff0c;先查看浏览器快捷方式&#xff0c;右键—>属性&#xff0c;看看文件位置最后面有没有被篡改成别的路径&#xff0c;如果有&#xff0c;删掉后面的路径就行 如果位置路径是正常的&#xff0c;那…

python2安装mysqldb_python2安装MySQLdb(windows同时装有python2和3)

命令行&#xff1a;py -2 -m pip install --upgrade pip #更新pippy -2 -m pip install MySQL-Python然后发现出错&#xff0c;按照提示进入 http://aka.ms/vcpython27 网站&#xff0c;下载 VCForPython27.msi 进行安装&#xff0c;又发现错误其实这时候已经安装成功&#xf…

mysql 常用函数

2019独角兽企业重金招聘Python工程师标准>>> 日期 now()和sysdate()在MySQL里now()和sysdate()函数都是表示取得当前时间&#xff0c;他们之间有什么区别 SELECT NOW(),SYSDATE(); 2015-12-13 09:13:23 2015-12-13 09:13:23 now()函数取的当前时间&#xff0c;取…

运维自动化之批量部署(cobbler)的使用

Cobbler的介绍1.cobbler的介绍Cobbler由python语言开发&#xff0c;是对PXE和Kickstart以及DHCP的封装。融合很多特性&#xff0c;提供了CLI和Web的管理形式。更加方便的实行网络安装&#xff0c;。同时&#xff0c;Cobbler也提供了API接口&#xff0c;使用其它语言也很容易做扩…

springboot定时发送短信_SpringBoot的定时任务

SpringBoot提供了非常简单的定时任务配置方法&#xff0c;不再像之前需要配置很多Quartz的文件了。首先看一个简单的静态任务&#xff1a;ConfigurationEnableSchedulingSlf4jpublic class StaticScheduledTasks {Autowiredprivate JCacheCacheManager jCacheCacheManager;Valu…

华为vrrp+dhcp+ospf+bfd

实验目标&#xff1a;在华为设备上配置vrrpdhcp,检测vrrp对dhcp是否有影响目标拓扑&#xff1a;配置思路&#xff1a;在R1&#xff0c;R2&#xff0c;R3&#xff0c;SW2&#xff0c;SW3上运行ospf路由协议以使全网路由互通&#xff0c;SW2&#xff0c;SW3上配置vrrpdhcp;SW4,SW…