python新手 小白也能懂 简单开放网站的爬虫小妙招 简单数据分析#爬取豆瓣Top250#爬取斗鱼首页热度排行
豆瓣网和斗鱼都是日常常用网站之一,但由于信息的公开性,对于反爬和防爬的防范力度都不是很强,可以简单爬取我们所需要的信息,很适合新手。跟着文章一步步走,一定可以操作实现!
1.准备工作:安装库
python很强大的一个功能就是有许多开放的库,因此想要做好爬虫和分析,需要安装几个库帮助我们。
1.requests
2.pandas
3.lxml
4.BeautifulSoup
如果安装失败,可以尝试用Tsinghua的路径
在终端台Terminal中输入 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple BeautifulSoup
requests
requests的作用是向网页发送一个请求,网页返回一个响应,然后获取响应的网页源码,再将里面的过滤,得到我们想要的数据
import requests
#以豆瓣网为例 url是目标的网址
url='https://movie.douban.com/top250'
#获取目标网页返回的内容
response=requests.get(url)
#输出文本形式
print(response.text)
#response的格式
<class 'requests.models.Response'>
#
2.网页查找信息
但我们并不是真正的浏览器,为了装的像一些,我们需要一个headers头字段来伪装一下自己,让自己看起来就像是一个真的浏览器。
打开豆瓣top250网页,摁F12,查看后台。找到Network,勾选上Preserve log之后刷新网页,点击左侧Name中是top250的文件,在右侧下拉找到Requeset Headers,里面就是我们需要的头内容。
Cookie是作为我们要爬取登陆后的信息,需要用到Cookie中的数据,这个豆瓣不需要登陆也能看到top250的信息
我们拿到头信息,将它定义成字典格式。
header
# 'User-Agent': 'Mozila/5.0 (Windows NT 10.1; WOW65) AppleWebkit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
headers={'User-Agent':'Mozila/5.0 (Linux;y; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/531.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/531.30'
,'Referer':'https://movie.douban.com/top250'
}
#不要用我的,我改过参数了,用你自己查到的
#Referer字段加上可以更加真实,更不容易被检测出来是爬虫
这一步可以跳过,代码爬取的速度是很快的,一秒中会频繁访问网页,这也不符合正常浏览器浏览网页的速度,因此,爬多之后你的ip有可能会被网页限制,我们可以创建一个线程池,里面放一些匿名ip,代替你自己本身的ip不易被限制,但豆瓣网页爬的不多的情况下一般不需要,可以不看这一段
#随意选了两个ip地址,大概率用不了
proxies= {
'http':'http://42.7.29.83:9999',
'https':'https://113.194.50.233:9999'
}
查找信息格式
我们再回到网页,摁F12,找到ELements,在里面找找找找到top1电影的框框,找到里面的div,右键选择copy->xpath,复制下来
就是这样://*[@id=“content”]/div/div[1]/ol
接下来我们运用lxml中的etree树功能,就像名字,我们先找到树的根部,也就是上面的那个//*[@id=“content”]/div/div[1]/ol,从这里开始发散的找其他节点的
- 中的,因此我们搜索根节点下面的li,然后我们在li中找啊找,最后找到了排名序号隐藏在 中,老方法,copy他的xpath
from lxml import etree
#因为内容都是在根节点下面的li中,所以我们直接将根路径带上li,就可以直接搜里面的内容
xp = etree.HTML(html)
s1 = xp.xpath('// *[ @ id = "content"] / div / div[1] / ol / li')
#在s1中搜索刚刚em的xpath,并输出text格式
ranks=s1.xpath('div/div[1]/em/text()')
#我们打印输出发现,拿到的是【1】,为了去掉这个讨厌的中括号,我们改进一下
ranks = str(s1.xpath('div/div[1]/em/text()'))[2:-2]
如法炮制,我们利用循环,拿到电影名,导演,评分,影评等数据
#循环外先定义几个数据
columns = ['排名','电影名称','导演','上映年份','制作国家','类型','评分','评价人数','短评']
list=[]
def get_data(html):
xp = etree.HTML(html)
s1 = xp.xpath('// *[ @ id = "content"] / div / div[1] / ol / li')
for i in s1:
ranks = str(i.xpath('div/div[1]/em/text()'))[2:-2]
titles=str(i.xpath('div/div[2]/div[1]/a/span[1]/text()'))[2:-2]
directors=i.xpath('div/div[2]/div[2]/p[1]/text()')[0].strip().replace("\xa0\xa0\xa0","\t").split("\t")[0]
infos=i.xpath('div/div[2]/div[2]/p[1]/text()')[1].strip().replace("\xa0","").split("/")
years=infos[0]
countrys=infos[1]
types=infos[2]
scores=i.xpath('div/div[2]/div[2]/div/span[2]/text()')[0]
scorenums=i.xpath('div/div[2]/div[2]/div/span[4]/text()')[0][:-3]
comments=str(i.xpath('div/div[2]/div[2]/p[2]/span/text()'))[2:-2]
#将每一项数据都加入到我们列表中
list.append([ranks,titles,directors,years,countrys,types,scores,scorenums,comments])
#接下来我们将数据整合,用前面定义的列名columns,用dataframe变成二维的,便于我们查看
d =pd.DataFrame(list,columns=columns)
d.to_excel('Top250(1).xlsx',index=False)
利用网址规律实现网页跳转
豆瓣Top250的电影排行,每一个页面只有25个,通过观察发现,每一页的网址都有规律,https://movie.douban.com/top250?start=25&filter=
每一页都是从25的倍数加一开始,即start=?,再利用循环
for i in range(0,251,25):
步长改成25,用format的格式给url变化赋值为i
url="https://movie.douban.com/top250?start={}&filter=".format(str(i))
res=requests.get(url,headers=headers)
html=res.text
#将返回的参数html传入前面获取数据的方法中
get_data(html)
这样,我们就拿到了top250的数据,并且生成了excel格式。
之后我们进行分析就好啦
爬取斗鱼直播间信息
接下来我们用另一种方法,BeautifulSoup来爬斗鱼的首页热度数据
和前面一样,我们获取到headers字段,设置好url,通过requests获取页面内容,然后获取text格式,通过BeautifulSoup树对内容进行提取,html.parser是bs4的html解析器。我们根据标签的id和class进行查找
查找到div标签下所有的li标签(即每个房间的内容信息),然后遍历这些信息,提取有用信息就好啦
import requests
from bs4 import BeautifulSoup as bs
import pandas as pd
headers={
'user-agent':'Mozilla/5.0 (Windows NTx'x'x'x WOW64) AppleWebKit/5xx (KHTML, like Gecko) Chrome/xxxxxxxx Safari/537.36'
}
url='https://www.douyu.com/directory/all'
list=[]
coclums=['房间名','主播名','类型','标签','热度']
response = requests.get(url, headers=headers)
html = response.text
html_tree = bs(html, 'html.parser')
host_infos = html_tree.find("div", {"class": "layout-Module-container layout-Cover ListContent"})
host_list = host_infos.find_all("li")
for i in host_list:
home_name = i.find("h3").get_text()
home_name1 = i.find("div", {"class": "DyListCover-userName"}).get_text()
home_type = i.find("span", {"class": "DyListCover-zone"}).get_text()
home_tag = i.find("span", {"class": "HeaderCell-label-wrap is-od"})
home_num = i.find("span", {"class": "DyListCover-hot"}).get_text()
list.append([home_name, home_name1, home_type, home_tag, home_num])
df = pd.DataFrame(list, columns=coclums)
df.to_excel("hot-100.xlsx", index=False)
数据分析
接下来我们进行简单的数据分析,以豆瓣Top250.xlsx为例进行分析。我们选择两种分析方法,一种直接在python内进行分析,一种转换为html可以放大图表。
我们用一种简单的方式分析数据,直接显示图表的方式,安装一个词云图(WordCloud)和正则表达式(re)的库,老方法不行就Tsinghua
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import pandas as pd
import re
def score():
data = pd.read_excel("Top250(1).xlsx")
#获取评分一栏的数据 values_counts()统计不同值的个数 和每个不同值出现的个数从大到小排列
xAxis=list(data["评分"].value_counts().sort_index().index)
yAxis=list(data["评分"].value_counts().sort_index().values)
plt.rcParams['font.sans-serif'] = ['SimHei']
list1=[]
for i in xAxis:
i=str(i)
list1.append(i)
plt.bar(list1,yAxis,label="评分状况",color ='steelblue',alpha=0.8)
plt.title("number-detail")
plt.xlabel("score")
plt.ylabel("number")
plt.legend()
plt.show()
把评分状况拿出来分析一下:
根据评价人数(即电影热度排名):
def comment():
data=pd.read_excel("Top251.xlsx")
list1=list(data["评价人数"])
list3=[]
for i in list1:
i=int(re.sub("\D","",i))
list3.append(i)
list2=list(data["电影名称"])
df=pd.DataFrame(data=list3,index=list2,columns=["评论数"])
df=df.sort_values(by="评论数",ascending=False)
xAxis=df.head(10).index
list3.sort(reverse=True)
yAxis=list3[0:10]
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(20, 10)) # 设置画布的尺寸
plt.barh(xAxis,width=yAxis,color='#6699CC',label='评论数(条)')
plt.show()
按照上榜导演执导的电影排名:
def director():
df=pd.read_excel('Top250(1).xlsx')
list1=df["导演"].value_counts(ascending=False).index
list2=df["导演"].value_counts(ascending=False).values
i=0
xAxis=[]
yAxis=[]
list3=[]
for i in range(10):
xAxis.append(list1[i])
yAxis.append(list2[i])
i+=1
plt.figure(figsize=(10,5))
for i in xAxis:
m=re.findall('[\u4e00-\u9fa5]+',i)
if len(m)>2:
list3.append(m[1]+m[2])
else:
list3.append(m[1])
list3.reverse()
yAxis.reverse()
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['xtick.labelsize'] = 10
a = plt.barh(list3, yAxis, color="deeppink")
#按照坐标每一行显示数量
for rect in a:
w = rect.get_width()
plt.text(w+0.05,rect.get_y() + rect.get_height() / 2, '%d' %
int(w), ha='left', va='center')
plt.show()
按照电影类型数量生成词云图:
def wordcloud():
df=pd.read_excel("Top250(1).xlsx")
list1=list(df["类型"])
list2=[]
f=open('data/log.txt','w')
for i in list1:
for j in range(0,len(i),3):
list2.append(i[j]+i[j+1])
#只能识别英文,我没有用jieba分割,就下载了中文文字包
wordcloud=WordCloud(background_color="white",width=300,height=150,
font_path=r'C:\Windows\Fonts\simfang.ttf',margin=2).generate_from_text(' '.join(list2))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
if __name__ =="__main__":
# score()
# comment()
# director()
wordcloud()
用html方式显示图标(更大更直观)
用年份进行分析,看看那些年份高产电影
import pandas as pd
import matplotlib.pyplot as plt
from flask import Flask
from flask import render_template
app =Flask(__name__)
这里需要引入几个新的库,matplotlib用于形成柱状图饼图等分析,flask可以框架启动浏览器打开html。如果遇到安装库不成功的问题,还是使用老方法:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
之后我们定义一个方法,用来分析年份的数据:
#app.py
#路由路径即http://127.0.0.1:5000/year
@app.route('/year')
def year():
#读取数据:
data = pd.read_excel("Top251.xlsx")
#value_counts()是一种查看表格某列中有多少个不同值的快捷方法,并计算每个不同值有在该列中有多少重复值。
#之后将值按大小排序,分别取索引(年份),和值(数量)作为横纵坐标
x = list(data["上映年份"].value_counts().sort_index().index)
y = list(data["上映年份"].value_counts().sort_index().values)
#柱状图的一些参数 字体等
plt.rcParams['font.family'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['xtick.labelsize'] = 0.1
#调用模板html
return render_template("bar.html",x=x,y=y)
if __name__=='__main__':
year()
之后编写一个html类型的界面 :“bar1.html”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/echarts.js"></script>
<script>
function bar() {
var first = document.getElementById("first")
var chart = echarts.init(first)
var option={
xAxis:{
data:{{x|safe}}
},
yAxis:{
data:{}
},
series:{
type:"bar",
data:{{ser|safe}}
}
}
chart.setOption(option)
}
</script>
</head>
<body>
<div id="first" style="width: 600px ;height:600px;border:2px solid aqua">
</div>
<div>
<button onclick="bar()">显示</button>
</div>
</body>
</html>
之后启动没有找到太好的方法,就使用Terminal中敲指令的方式吧
python>python .\app.py
运行后点击:http://127.0.0.1:5000 在浏览器中网址后面+/year
即:http://127.0.0.1:5000/year 点击显示按钮,做的不太好看,凑乎看
这样的粗略图显示不全年份,我们拖动下面的进度条,让年份显示的更加清晰:
可见,改革开放对电影行业影响很大啊,无论中外(改革春风吹满地!)