1. 程式人生 > >MongoDB+Python 爬取寶寶樹問答模組並進行簡單分析

MongoDB+Python 爬取寶寶樹問答模組並進行簡單分析

前幾天剛學了MongoDB的。聽說有諸多好處。邊想著來感受下。

恰逢一好友職位調整,需要了解目前母嬰市場圍繞的重心。

所以便我去  寶寶樹  ,爬取問答,看看媽媽們都在想什麼。

整體思路

1,爬取各大問題分類及其連結。分成一級分類,二級分類。比如準備懷孕 - 懷孕前的準備。

2,直接生成所有需要爬取的連結(一個已解決問題下,最多隻有250頁的問題。多了爬不下來。所以只有少於250頁的問題才是完整的。)

3,根據連結進行爬取,並且儲存在MongoDB中中。

4,進行分析

原始碼

1,爬取分類及網址

import requests
from bs4 import BeautifulSoup
import time,re
from tqdm import tqdm
import numpy as np
import pandas as pd

list_userAgent=['Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19',
'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'Mozilla/5.0 (Linux; U; Android 2.2; en-gb; GT-P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1',
'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0',
'Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0',
'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36',
'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
'Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3',
'Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A101a Safari/419.3']


#獲取二級標題及URL.
url_first = 'http://www.babytree.com/'

for row in soup.find("div",{"id":"know-cat-dir"}).find("dl").find_all("dd"):
    for i in row.find_all("li"):

        url = url_first + re.search('<a href="(.*?)">(.*?)</a>',str(i)).group(1)
        question = re.search('<a href="(.*?)">(.*?)</a>',str(i)).group(2)
        print(url,',',question)

#獲取一級分類
for row in soup.find("div",{"id":"know-cat-dir"}).find_all("dt"):
    print(row)

#因為數量比較少,直接複製到Excel中

2,生成所有的URL,儲存在MongoDB的中。爬一條,刪一條。

#讀取剛才的一級標題二級標題的URL
data=pd.read_csv("C:\\Users\\Jack\\Desktop\\url_baobaoshu.csv",encoding = "UTF-8")
data=data.values.tolist() 

#獲取最大頁數. 
def get_max_page(url):
    r = requests.get(url)
    html = r.text.encode(r.encoding).decode()
    soup= BeautifulSoup(html,'html.parser')
    return int(re.search('<span class="page-number">共(.*?)頁</span>',str(soup)).group(1))

#構建url-list . 方便直接進行爬取
list_url = []
for row in data:
    first_title=row[2]
    second_title=row[1]
    url = row[0]
    url = re.sub(r'tab~B',r'tab~D',url)
    max_page = get_max_page(url)
    for i in range(1,max_page+1):
        url_real = url + ',pg~%s'%(i)
        list_url.append([first_title,second_title,url_real])
    time.sleep(1)

#插入URL到MONGODB.   firstTitle,secondTitle,url
list_dic = []
for row in list_url:
    list_dic.append({"firstTitle":row[0],"secondTitle":row[1],"URL":row[2]})
url_col.insert_many(list_dic)


總計生成了14206條連結。

3,根據MongoDB的裡的連結,進行爬蟲,寫入到的MongoDB中,並刪去已完成的連結。

def get_detail(firstTitle,secondTitle,url):
    global list_written,i,soup
    list_written=[]
    while 1:
        try:
            r = requests.get(url,headers=headers)
            break
        except requests.ConnectionError:
            time.sleep(10)
    html = r.text.encode(r.encoding).decode()
    soup= BeautifulSoup(html,'html.parser')
    #獲取單個 已解決 問題
    for i in soup.find_all("li", {"class":"list-item"}):
        try:
            id_question = re.search('<p class="list-title"><a href="http://www.babytree.com/ask/detail/([0-9]+)" target="_blank">(.*?[\n\r\s]*.*?)</a></p>',str(i)).group(1)
            question = re.search('<p class="list-title"><a href="http://www.babytree.com/ask/detail/([0-9]+)" target="_blank">(.*?[\n\r\s]*.*?)</a></p>',str(i)).group(2)
            answer = re.search('<span class="excerpt">(.*?)</span>',str(i)).group(1)
            list_written.append([firstTitle,secondTitle,id_question,question,answer])
        except AttributeError :
            print('-',end='')
    try:
        list_dic = []
        for row in list_written:
            list_dic.append({"firstTitle":row[0],"secondTitle":row[1],"id_question":row[2],"question":row[3],"answer":row[4]})
        com_col.insert_many(list_dic)
    except TypeError:
        pass

    time.sleep(np.random.random()*3)
#在jupyter中執行. 沒有進度條提示.
while [i for i in url_col.find()]:
    for row in  url_col.find() :
        headers={}
        headers['User-Agent'] = list_userAgent[np.random.randint(0,9)]
        first = row['firstTitle']
        second = row['secondTitle']
        url = row['URL']
        get_detail(first,second,url)
        url_col.delete_one({"URL":url})
print('目測已完結')


#--------------------

#放在pycharm中可執行
while [i for i in url_col.find()]:
    pbar = tqdm([i for i in url_col.find()], ncols=50, desc='進度')
    for char in pbar:
        row = char
        headers = {}
        headers['User-Agent'] = list_userAgent[np.random.randint(0, 9)]
        first = row['firstTitle']
        second = row['secondTitle']
        url = row['URL']
        get_detail(first, second, url)
        url_col.delete_one({"URL": url})
print('目測已完結')

上面特意放上了兩個版本的執行。jupyter不支援tqdm。所以挺尷尬的...專門在jupyter lab中寫完,放到pycharm中執行。

下面的是有進度條的,就是連結的個數進度。可以看單個連結的爬蟲速度。第一個展示不夠直觀。

最後生成是這個樣子。

4,分析

從簡單的分佈來看,嬰兒期0-1歲是最受關注的一個區間。

也可以用詞雲圖來看使用者的傾向性

list_question = [i["question"] for i in com_col.find({"firstTitle":"生活消費"}) ]

stopWords='''怎麼樣 怎麼辦 什麼 怎麼 可以 怎麼回事 哪裡 哪個 多少
        如何 哪些 有沒有 沒有 知道 比較 哪家 現在 好不好 不好 適合 一下 請問 為什麼 多少 大家'''

        
import jieba,re
from datetime import datetime
t1 = datetime.now()
list_jieba = []
for row in list_question:
    for i in jieba.cut_for_search(row):
        word= (re.sub('[0-9.:\/\(\)\[\]\s:]+|\\r|\\n|[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]','',i))
        if word != '' and len(word) >1  and word not in stopWords.split(' ') :
            list_jieba.append(word)
t2 = datetime.now()
print('takes',(t2-t1).seconds,'seconds')

import pandas as pd
df = pd.DataFrame(list_jieba,columns=['word'])
df.insert(1,"index","")

df2 = df.groupby('word').count().sort_values(by = 'index',axis = 0,ascending = False)
df2.insert(0,"word",[i for i in df2.index])
wordlist = df2.values.tolist()

from pyecharts import WordCloud
wordcloud = WordCloud('詞雲','Made By Jack',width=800, height=620)
wordcloud.add("",[i[0] for i in wordlist], [i[1] for i in wordlist], word_size_range=[10, 80],shape='pentagon')
wordcloud

去掉一些stopWords(常見的介詞等)。圍繞在最中間的當然是寶寶啦〜 

因為篩選了firstTitle為生活消費。因此出現的比如說亞麻啦,醫院啦,籽油啦,減肥,奶昔啦,還是可以想象得到的。

如果篩選條件為嬰兒期0-1歲的問題,則

感覺用蟒蛇實現篩選,還是有點麻煩,不太方便展示。

匯出為CSV,匯入POWER BI試試。

在互動方面,強太多了。

只需要匯出即可。

感想

1,Python的在視覺化展示這一塊,真心沒有其他BI工具來得方便,雖然很快

2,Python的在資料清洗方便,基於面對物件的理念,真的是太舒服了。 

3,Python的結合BI工具,真心好好好用

4,MongoDB的比Mysql的好用。但是如果資料比較簡單的話..用CSV更快,哈哈哈