前几天刚学了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更快,哈哈哈