学习任何新事物,都须要先搭建起学习框架。php
一般咱们会从「基础知识」、「案例实操」两个板块切入,构建起本身的学习闭环。html
1、关于「基础知识」python
对于想快速了解知识关键要点的新手,如下是比较推荐的学习素材:编程
MOOC课程:Python语言程序设计、Python网络爬虫与信息提取浏览器
参考书籍:《利用Python进行数据分析》、《Python编程:从入门到实践》bash
2、关于「案例实操」微信
验证本身是否真正理解知识并能应用的最佳方式,就是经过案例完成实践操做。网络
分享案例
做为爬虫新手,如何利用Python爬取NBA球员数据。
app
一、搭建工做环境框架
传统方式:对于Win用户,须要本身在本地搭建运行环境。
准备工做:
安装Package
说明:
以上工具,除Python环境外,皆为Python的第三方库。Windows环境下经过cmd的pip install命令安装。对于Mac用户,虽没那么复杂,但一样会须要花费时间与精力。
你们会发现,按以上步骤搭建工做环境,是个特别费时费力的事儿,P二、P3的兼容性问题也很突出。
那么有没有更好的方法呢?答案是,有的。
像科赛网,针对数据科学家人群,重点打造了K-Lab在线数据分析协做平台。它涵盖了Python、R等多种主流语言,完成90%以上数据分析&挖掘相关库的部署,避免了搭建本地环境配置时遇到的各类问题,帮助数据人才真正实现「在线」作数据分析,提升效率,专一价值创造。
二、搭建工做流
1)选取目标官网:NBA中文数据网站
2)导入库
#引入主要的爬取工具:
import requests
from bs4 import BeautifulSoup
#如下是数据的清洗和存储所需的辅助工具
import re
import numpy as np
import pandas as pd
复制代码
完成导入后,获取每一个球员各个赛季单场比赛的基础数据(CSV文档格式):
3)找到页面,批量爬取
样例:LeBron James的详情页,该网站数据源相对规整,URL设置易找规律,方便抓取。
说明:为了实现自动批量抓取,爬取时通常须要让爬虫先爬取列表页,再根据列表页的索引连接爬取相应的详情页。但在该项目并不须要如此,从连接1、连接2能够看出其中规律。
将须要关注的参数用粗体表示:
爬取时,咱们只须要改动这些数据就能实现全站资源的爬取,很是适合新手。
4)解析页面
推荐在Chrome浏览器的开发者模式下解析页面,它能快速定位到所需内容。
图中蓝标显示的Table标签即是须要抓取的表格。
关于table标签:
table标签有两个子标签thead、tbody。
5)将表格内容搬运到本地
首先,经过fillframe函数,将网页上的表格转换成一个pandas的DataFrame表格对象。
def fillframe(tbody,index):
#这里只使用tbody标签,表头经过index传入,index是一个list
frame=pd.DataFrame()
if tbody:
all_tr=tbody.find_all('tr')
for tr in all_tr:
dic={}
all_td=tr.find_all('td')
i=-1
for td in all_td:
if i==-1:
#能够发现,网页表格中每行的第一格都是空的,因此咱们须要将其跳过。
i+=1
continue
else:
dic[index[i]]=td.string
i+=1
frame=pd.concat([frame,pd.DataFrame(dic,index=[0])],ignore_index=True)
return frame
复制代码
其次,用fillindex函数将fillframe函数生成index。
def fillindex(thead):
index=[]
if thead:
all_th=thead.tr.find_all('th')
i=-1
for th in all_th:
if i==-1:
i+=1
continue
else:
index.append(th.string)
i+=1
return index
复制代码
通过以上操做,不难发现,网页上表格的表头可能有歧义。好比它将投篮的命中数和三分的命中数两项数据的索引都设置为了命中。为了保险起见,建议手动设置index。
index=['球员','赛季','结果','比分','首发','时间','投篮','命中','出手','三分', '三分命中','三分出手','罚球','罚球命中','罚球出手','篮板','前场','后场','助攻','抢断','盖帽','失误','犯规','得分']
复制代码
6)开始爬取页面,并提取table
提取过程当中,因为每一个球员的数据条目数不一样,不能肯定球员数据的页数。
能够考虑给spider函数设置为“在页面没法正常读取或读取的页面中找不到table标签时返回False值”。
def spider(page,player_id,gametype,index):
url='http://www.stat-nba.com/query.php?page='+str(page)+'&QueryType=game&GameType='+str(gametype)+'&Player_id='+str(player_id)+'&crtcol=season&order=1'
r=requests.get(url,timeout=30)
if r.status_code==200:
demo=r.text
soup=BeautifulSoup(demo,"html.parser")
data=soup.find('div',{'class':'stat_box'})
if not data: #找不到数据表格时退出
return False
table=data.find('table')
if table:
tbody=table.find('tbody')
return fillframe(tbody,index)
else: #数据表格为空时退出
return False
else: #页面读取失败时退出
return False
复制代码
其次,用update函数保存更新已爬取好的DataFrame。
def update(frame,path,filename):
try: #尝试读取文件filename
frame0=pd.read_csv(path+'\\'+filename)
except: #若是文件已经存在,则更新它
frame.to_csv(path+'\\'+filename,index=False,encoding='utf-8')
else: #不然建立名为filename的文件
frame0=pd.concat([frame0,frame],ignore_index=True)
frame0.to_csv(path+'\\'+filename,index=False,encoding='utf-8')
复制代码
最后,着手设计主函数,来控制循环以及存储数据。
frame_player=pd.DataFrame()
gametype='season'
for player_id in range(1862,1863):
#这里仅爬取一位球员(James)测试,须要正式爬取请改成range(1,4450)
page=0
flag=True
while flag:
result=spider(page,player_id,gametype,index)
if type(result)==bool and not result: #返回False时
flag=False
break
else: #爬取成功时读取表格
frame_player=pd.concat([frame_player,result],ignore_index=True)
page+=1
复制代码
7)测试阶段:爬取一位球员数据,结果以下:
frame_player.head()
复制代码
接下来,就可使用以前定义的update函数将frame_player保存到本地,也能够在每次while循环结束时运行一次update函数以起到实时更新的效果。
注意:实时更新完之后需执行frame_player=DataFrame()语句,将frame_player清空以免数据重复。
以上即是完整的爬取数据操做过程。
8)常见问题解答
因为网站自身的编码缘由,爬取时可能会遇到全部中文字符都成为乱码,以下:
frame_player.head()
复制代码
对该数据集,能够手动输入Index来解决表头乱码。
爬取球员英文姓名解决球员姓名乱码,具体的函数以下:
def getname(player_id):
r2=requests.get('http://www.stat-nba.com/player/'+str(player_id)+'.html',timeout=30)
if r2.status_code==200:
demo2=r2.text
soup2=BeautifulSoup(demo2,"html.parser")
name_source=soup2.find('div',{'class':"playerinfo"}).find('div',{'class':'name'})
if re.findall('[A-z]* [A-z]*',name_source.contents[0]):
name=re.findall('[A-z]* [A-z]*',name_source.contents[0])[0]
else:
name=np.nan
else:
name=np.nan
return name
复制代码
PS:爬虫还有不少能够优化的空间,好比控制每次发送请求的时间间隔防止IP被封,爬取球队名称作映射来解决比分中的乱码。
咱们已在科赛网上建立该爬虫项目,能够看到完整的实现代码。
建议新手萌登录官网在线实现运行,不只仅只停留在阅读层面。
操做步骤
登陆「kesci.com」- 点击「K-Lab」- 点击「项目」- 在「关键词」框内输入「爬取」便可查看该项目的爬虫完整代码,一键Fork、在线运行。
操做过程当中有任何疑问,可添加科赛网工做人员微信号(小科:kesci_jack),备注:掘金