小豬的Python學習之旅 —— 17.Python數據分析:我主良緣交友瞭解下

小豬的Python學習之旅 —— 17.Python數據分析:我主良緣交友瞭解下

標籤:Python


一句話概括本文

爬取我主良緣交友所有的妹子信息,利用Jupyter Notebook對五個方面:
身高,學歷,年齡,城市和交友宣言進行分析,並把分析結果通過pyecharts
進行數據可視化。


引言

本節應該是Python數據分析入門的最後一節了,數據分析的水可是深的很:
大數據處理,機器學習,深度學習,NLP等,當前能夠抓下數據,用好
pandas,numpy和matplotlib基礎三件套,完成數據可視化就夠了。
上節分析拉勾網的Android招聘數據,沒什麼特別的感覺,我覺得
可能是數據太少了,加起來也就700來條。還有Jupyter Notebook
pyecharts沒有去試試,有點美中不足,於是乎我又想着抓點
什麼分析分析。一天早上,日常出地鐵,電視上依舊無腦放着這樣
的廣告:我主良緣的公衆號,可以在線找對象的公衆號…
坐過深圳地鐵的應該不會陌生…突然靈光一閃,要不抓一波
我主良緣,分析分析都是些怎麼樣的妹子在找對象?
有idea了,接着就是看下抓數據的難度了,回公司直接打開
官網,點開交友頁:

http://www.lovewzly.com/jiaoyou.html

F12打開抓包,大概看了抓取的難度不大,接着就開始爬數據環節啦~


1.數據抓取

列表滾動到底部加載更多,猜測是Ajax動態加載數據,直接攔截XHR

有點明顯,隨手點開一個:

喲,直接就是我們想要的數據了,接着研究下請求規律。
篩選條件都勾上,獲取一波所有的參數,然後再自行搭配。

抓包看下參數:

字段 含義
startage 21 起始年齡
endage 30 截止年齡
gender 2 性別,1代表男,2代表女
cityid 52 城市id,這個通過查看頁面結構可以獲取熱門的幾個城市id
startheight 161 起始身高
endheight 170 截止身高
marry 1 結婚狀態,1未婚,3離異,4喪偶
astro 2 星座,看下錶
lunar 2 生肖,看下錶
education 40 教育水平,看下錶
salary 2 收入,看下錶
page 1 頁數,一頁20條數據

抓的鏈接是:http://www.lovewzly.com/api/user/pc/list/search?
接着就是請求頭模擬了:

然後呢,我想抓所有未婚的妹子的信息,查詢參數如下:

看下返回的Json,能拿到的參數如下:

字段有:

頭像出生年份省份性別, 學歷身高交友宣言城市用戶id暱稱

東西都齊了,接着就是把爬到的數據寫到csv裏了,不難寫出這樣的代碼:

沒用代理,這裏依舊是隨緣休眠,避免訪問過於頻繁ip被封,

接着掛着就好,大概要爬1.3個小時(沒有好的代理ip,不用多進程就這樣~)
抓取成功後的數據:

總共有15521條數據,可以,很nice,接着開始胡亂分析環節。


2.安裝Jupyter Notebook與pyecharts

在開始數據分析前,我們另外安裝兩個東西:

Jupyter Notebook:一個非常適合做數據分析的工具,可以在上面寫
代碼,運行代碼,寫文檔,做數據可視化展示。舉個例子:
在Pycharm上寫代碼,matplotlib繪製的圖形要麼通過plt.show()展示出來
要麼保存爲一個圖片文件,然後你要看的時候把圖片文件打開。
而使用Jupyter直接就可以看到,配合支持文檔編寫,你都不需要報告了,
利用可以直接運行的特點,很多人都拿來直接寫Python教程,非常方便。
安裝也很簡單,直接通過pip命令安裝即可。

pip install jupyter notebook

安裝完成後,命令行鍵入:jupyter notebook 會自動打開一個網頁

點擊New,選擇一個內核,比如Python3,然後會新建一個ipynb後綴的文件,
點開會出現下面的頁面:

頁面比較簡單,自己點開摸索摸索吧,加號是新建一個單元格,
剪刀圖標是刪除單元格,接着是複製粘貼單元格,單元格上下移,
運行,終止。Code那裏下拉可以選擇單元格編寫的內容;

運行的快捷鍵是:shift + enter,大概就這些,更多可見下述視頻教程:

Jupyter Notebook Tutorial: Introduction, Setup, and Walkthrough

再接着是安裝pyecharts,這是一個用於生成Echarts圖表的類庫,
Echarts是百度開源的一個數據可視化JS 庫。用Echarts生成的圖可視化
效果非常棒,pyecharts是爲了與 Python 進行對接,方便在Python中直接
使用數據生成圖,生成結果是一個html文件,用瀏覽器打開即可看到效果。

相關文檔

安裝方法同樣也很簡單,直接pip走一波:

pip install pyecharts

安裝完之後,直接編寫代碼繪製地圖,地圖區域是無法顯示,你需要
另外安裝地圖文件:

pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg

特別註明,中國地圖在 echarts-countries-pypkg 裏。
一般安裝第一個就夠了,其他看自己吧。
到此就準備好了,接下來開始編碼進行數據分析~


3.開始數據分析

這裏我們直接在Jupyter寫代碼進行數據分析,命令行鍵入: jupyter notebook
打開,然後來到我們的目錄下,新建一個WZLY.ipynb的文件,進入後就可以
開始編寫代碼了。

1.讀取CSV文件裏的數據

2.分析身高

運行結果


3.分析學歷

結果分析


4.分析年齡

運行結果


5.分析城市

運行結果


6.分析交友宣言

輸出結果


小結

以上就是對通過爬蟲採集到的我主良緣妹子交友信息進行的簡單的數據分析,
主要目的還是試試Jupyter Notebook和pyechars這兩個東東,結果還是沒
分析出什麼特別有用的東西,分析完大概知道了這樣一些信息:

  • 1.妹子身高:集中在150-170cm之間,達到了94.21%的佔比;
  • 2.妹子學歷:本科和大專是主力軍;
  • 3.妹子年齡:26-30歲的最多,18-25次之,31-40歲的大齡剩女也挺多的;
  • 4.妹子城市分佈:大部分還是集中在北深上廣,其次杭州,南京,廈門,福州,成都,武漢,青島;
  • 5.妹子中意的對象特點:前八依次是責任心上進心事業心熱愛生活性格開朗脾氣好孝順父母安全感

好吧,關於Python做數據分析就到這裏了,數據分析是一個方向,但是目前不會深究:
行業大數據 + 機器學習框架 + 深度學習算法 => 人工智能
so,不用我說什麼了,後面能有適合的環境,有這樣的機會研究這些東西,
再續寫相關的文章吧。後面的文章會寫回Python爬蟲,多進程,分佈式爬蟲,
爬蟲與反爬蟲的策略研究,學習Redis,Mongodb,MySQL,Flask寫個自己
APP使用的API,Django,弄自己的網站等等,敬請期待~


附:最終代碼(都可以在:https://github.com/coder-pig/ReptileSomething 找到):

import requests as rq
import config as c
import tools as t
import pandas as pd
import numpy as np
import time
import random
import sys
from pyecharts import Bar, Pie, Funnel, Radar, Geo, WordCloud
import jieba as jb
import re
from collections import Counter

result_save_file = c.outputs_logs_path + 'wzly.csv'

# Ajax加載url
ajax_url = "http://www.lovewzly.com/api/user/pc/list/search?"

# 模擬請求頭
ajax_headers = {
    'Accept': 'application/json, text/javascript, */*; q=0.01',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    'Connection': 'keep-alive',
    'Host': 'www.lovewzly.com',
    'Referer': 'http://www.lovewzly.com/jiaoyou.html',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 '
                  'Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
}

# post請求參數
form_data = {'gender': '2', 'marry': '1', 'page': '1'}

# csv表頭
csv_headers = [
    '暱稱', '用戶id', '頭像', '身高', '學歷', '省份',
    '城市', '出生年份', '性別', '交友宣言'
]

height_interval = ['140', '150', '160', '170', '180']  # 身高範圍
edu_interval = ['本科', '大專', '高中', '中專', '初中', '碩士', '博士', '院士']  # 學歷範圍
age_interval = [
    ('18-30', 8000), ('26-30', 8000), ('31-40', 8000),
    ('41-50', 8000), ('50以上', 8000),
]  # 學歷範圍

word_pattern = re.compile('[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?“”、~@#¥%……&*()(\d+)]+')


# 獲取每頁交友信息
def fetch_data(page):
    while True:
        try:
            form_data['page'] = page
            print("抓取第:" + str(page) + "頁!")
            resp = rq.get(url=ajax_url, params=form_data, headers=ajax_headers)
            if resp.status_code == 200:
                data_json = resp.json()['data']['list']
                if len(data_json) > 0:
                    data_list = []
                    for data in data_json:
                        data_list.append((
                            data['username'], data['userid'], data['avatar'],
                            data['height'], data['education'], data['province'],
                            data['city'], data['birthdayyear'], data['gender'], data['monolog']))
                    result = pd.DataFrame(data_list)
                    if page == 1:
                        result.to_csv(result_save_file, header=csv_headers, index=False, mode='a+')
                    else:
                        result.to_csv(result_save_file, header=False, index=False, mode='a+')
            return None
        except Exception as e:
            print(e)


# 分析身高
def analysis_height(data):
    height_data = data['身高']
    height = (height_data.loc[(height_data > 140) & (height_data < 200)]).value_counts().sort_index()
    height_count = [0, 0, 0, 0, 0]
    for h in range(0, len(height)):
        if 140 <= height.index[h] < 150:
            height_count[0] += height.values[h]
        elif 150 <= height.index[h] < 160:
            height_count[1] += height.values[h]
        elif 160 <= height.index[h] < 170:
            height_count[2] += height.values[h]
        elif 170 <= height.index[h] < 180:
            height_count[3] += height.values[h]
        elif 180 <= height.index[h] < 190:
            height_count[4] += height.values[h]
    return height_count


# 分析學歷
def analysis_edu(data):
    return data['學歷'].value_counts()


# 分析年齡
def analysis_age(data):
    age_data = data['出生年份']
    age = (age_data.loc[(age_data >= 1956) & (age_data <= 2000)]).value_counts().sort_index()
    age_count = [0, 0, 0, 0, 0]
    for h in range(0, len(age)):
        if 1993 <= age.index[h] <= 2000:
            age_count[0] += age.values[h]
        elif 1988 <= age.index[h] <= 1992:
            age_count[1] += age.values[h]
        elif 1978 <= age.index[h] <= 1987:
            age_count[2] += age.values[h]
        elif 1968 <= age.index[h] <= 1977:
            age_count[3] += age.values[h]
        elif age.index[h] < 1968:
            age_count[4] += age.values[h]
    return age_count


# 分析城市分佈
def analysis_city(data):
    city_data = data['城市'].value_counts()
    city_list = []
    for city in range(0, len(city_data)):
        if city_data.values[city] > 10:
            city_list.append((city_data.index[city], city_data.values[city]))
    return city_list


# 詞頻分佈
def analysis_word(data):
    word_data = data['交友宣言'].value_counts()
    word_list = []
    for word in range(0, len(word_data)):
        if word_data.values[word] == 1:
            word_list.append(word_data.index[word])
    return word_list


# 繪製身高分佈柱狀圖
def draw_height_bar(data):
    bar = Bar("妹子身高分佈柱狀圖")
    bar.add("妹子身高", height_interval, data, bar_category_gap=0, is_random=True, )
    return bar


# 繪製身高分佈餅圖
def draw_height_pie(data):
    pie = Pie("妹子身高分佈餅圖-圓環圖", title_pos='center')
    pie.add("", height_interval, data, radius=[40, 75], label_text_color=None,
            is_label_show=True, legend_orient='vertical', is_random=True,
            legend_pos='left')
    return pie


# 學歷漏斗圖
def draw_edu_funnel(data):
    funnel = Funnel("妹子學歷分佈漏斗圖")
    funnel.add("學歷", edu_interval, data, is_label_show=True,
               label_pos="inside", label_text_color="#fff", title_top=50)
    return funnel


# 年齡雷達圖
def draw_age_radar(data):
    radar = Radar("妹子年齡分佈雷達圖")
    radar.config(age_interval)
    radar.add("年齡段", data, is_splitline=True, is_axisline_show=True)
    return radar


# 城市分佈地圖
def draw_city_geo(data):
    geo = Geo("全國妹子分佈城市", "data about beauty", title_color="#fff",
              title_pos="center", width=1200,
              height=600, background_color='#404a59')
    attr, value = geo.cast(data)
    geo.add("", attr, value, visual_range=[10, 2500], visual_text_color="#fff",
            symbol_size=15, is_visualmap=True)
    return geo


# 交友宣言詞雲
def draw_word_wc(name, count):
    wc = WordCloud(width=1300, height=620)
    wc.add("", name, count, word_size_range=[20, 100], shape='diamond')
    wc.render()


if __name__ == '__main__':
    if not t.is_dir_existed(result_save_file, mkdir=False):
        for i in range(1, 777):
            time.sleep(random.randint(2, 10))
            fetch_data(i)
    else:
        raw_data = pd.read_csv(result_save_file)
        word_result = word_pattern.sub("", ''.join(analysis_word(raw_data)))
        words = [word for word in jb.cut(word_result, cut_all=False) if len(word) >= 3]
        exclude_words = [
            '一輩子', '不相離', '另一半', '業餘時間', '性格特點', '茫茫人海', '男朋友', '找對象',
            '談戀愛', '有時候', '女孩子', '哈哈哈', '加微信', '興趣愛好',
            '是因爲', '不良嗜好', '男孩子', '爲什麼', '沒關係', '不介意',
            '沒什麼', '交朋友', '大大咧咧', '大富大貴', '聯繫方式', '打招呼',
            '有意者', '晚一點', '哈哈哈', '以上學歷', '是不是', '給我發',
            '不怎麼', '第一次', '越來越', '遇一人', '擇一人', '無數次',
            '符合條件', '什麼樣', '全世界', '比較簡單', '浪費時間', '不知不覺',
            '有沒有', '尋尋覓覓', '自我介紹', '請勿打擾', '差不多', '不在乎', '看起來',
            '一點點', '陪你到', '這麼久', '看清楚', '身高體重', '比較慢', '比較忙',
            '多一點', '小女生', '土生土長', '發消息', '最合適'
        ]
        for i in range(0, len(words)):
            if words[i] in exclude_words:
                words[i] = None
        filter_list = list(filter(lambda t: t is not None, words))
        data = r' '.join(filter_list)
        c = Counter(filter_list)
        word_name = []  # 詞
        word_count = []  # 詞頻
        for word_freq in c.most_common(100):
            word, freq = word_freq
            word_name.append(word)
            word_count.append(freq)
        draw_word_wc(word_name, word_count)

來啊,Py交易啊

想加羣一起學習Py的可以加下,智障機器人小Pig,驗證信息裏包含:
PythonpythonpyPy加羣交易屁眼 中的一個關鍵詞即可通過;

驗證通過後回覆 加羣 即可獲得加羣鏈接(不要把機器人玩壞了!!!)~~~
歡迎各種像我一樣的Py初學者,Py大神加入,一起愉快地交流學♂習,van♂轉py。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章