前言:最近刚入门Python,在网上各种乱逛,稍微涉猎了一下Python爬虫,就想自己爬个东西练练手,加上之前自己也算是个魔方玩家,所以就想着把所以中国魔方选手的成绩都爬取保存下来,之后再对其做分析。
Python版本:3.7.0
使用方式:resquests+beautifulsoup
网站:https://cubingchina.com/results/rankings
分析页面
打开成绩页面,发现所以的选手信息都在一张表格里,打开开发者工具,发现个有意思的东西:每个选手所在行的class不同,单数是odd,双数是even,所以待会儿定位数据位置的时候得稍微注意一下儿了。
接着到底部,看到有下一页和末页的按钮,都在<li>标签下的<a>标签下,class分别是next和last
接着看后面的页面都是一样的,最后看一下最后一页,发现虽然下一页和末页的链接不能点击,但是在html文件里面是有链接的,这样就不好判断怎么是最后一页了。我处理的方式有点蠢,在抓取第一页的时候就提取出最后一页的地址,然后循环条件是下一页链接和末页链接不等,最后单独处理末页。
爬取数据
首先打开粗饼页面
import requests
url = ‘https://cubingchina.com/results/rankings’
response = requests.get(url)
response.encoding='utf-8'
print(response)
然后发现,403了,不让访问
请教了下学长,说可以尝试一下模拟header,然后加了这么一句
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}
在请求的时候加上header,成功了
接着就把这块封装成一个函数`
def get_html(url):
'''
根据url返回相应的html对象
'''
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}
response = requests.get(url, headers=headers)
response.encoding='utf-8'
html = response.text
# print(response)
return html
然后用beautifulsoup解析,用的是lxml方式(其实我还不明白这个是怎么用的)
from bs4 import BeautifulSoup
def get_soup(html):
'''
根据HTML返回beautifulsoup对象
'''
soup = BeautifulSoup(html, 'lxml')
return soup
然后获取每一页100位选手的信息
我们需要的是选手的排名,姓名,成绩,比赛以及日期
def get_rank_list(soup):
'''
使用beautifulsoup解析网页,取得选手信息
返回选手信息列表
'''
# 之前分析过,所以选手的信息在一张表格中,查看html代码获取表格的信息,提取出信息
rank_text_list = soup.find('table', {'class': 'table table-bordered table-condensed table-hover table-boxed'})
# 第一个tr是表头信息,所以就舍弃了
rank_text_list = rank_text_list.find_all('tr')[1:]
rank_list = []
for rank_text in rank_text_list:
# 所有的信息都在td标签里
rank_text = rank_text.find_all('td')
# 排名
rank = rank_text[1].extract().text
# 姓名
name = rank_text[2].extract().text
# 成绩
result = rank_text[4].extract().text
# 比赛
competitive = rank_text[5].extract().text
# 日期
date = rank_text[6].extract().text
# 把所有数据封装成一个元组,然后添加到选手成绩列表里
item = (rank, name, result, competitive, date)
rank_list.append(item)
return rank_list
接着把爬到的数据写入到csv文件里
def writer_file(rank_list, flag=''):
'''
写入csv文件
'''
header = ('排名', '姓名', '成绩', '比赛', '日期')
with open('333_single_China.csv', 'a', encoding='utf-8', newline='') as file:
writer = csv.writer(file)
if flag == 'first':
writer.writerow(header)
for rank in rank_list:
writer.writerow(rank)
爬取完一个页面的信息后,得继续爬下一页
def get_next_url(soup):
'''
获取下一页地址
'''
url_text = soup.find('li', {'class': 'next'})
url_text = url_text.find('a')
# 因为是相对地址,所以还需要拼接一下网站的主地址,直接用字符串拼接是不是有点low啊(小声BB)
main_url = 'https://cubingchina.com'
url = main_url + url_text.get('href')
return url
大体需要写好了,最后组合到main函数里
def main():
start_url = 'https://cubingchina.com/results/rankings'
# 先处理第一页,获取末页地址
html = get_html(start_url)
soup = get_soup(html)
# print(soup)
# 排名写入文件
rank_list = get_rank_list(soup)
# print(rank_list)
writer_file(rank_list, 'first')
print('第1页下载完成')
# 获取下一页url
next_url = get_next_url(soup)
# 获取最后一页url
last_text = soup.find('li', {'class': 'last'})
last_text = last_text.find('a')
last_url = main_url + last_text.get('href')
# 当下一页链接不等于末页链接是,接着运行
i = 2
while next_url != last_url:
html = get_html(next_url)
soup = get_soup(html)
rank_list = get_rank_list(soup)
writer_file(rank_list)
next_url = get_next_url(soup)
print('第{}页下载完成'.format(i))
i += 1
# 下载获取最后一页
html = get_html(next_url)
soup = get_soup(html)
rank_list = get_rank_list(soup)
writer_file(rank_list)
print('第{}页下载完成'.format(i))
大概就是这样,爬出的数据如下,用excel处理了下,看着舒服点
最后把源码完整贴出来
'''
功能:爬取粗饼网所有人三阶单次成绩
作者:Davion
版本:V1.0
日期:2018/03/12
'''
import requests
from bs4 import BeautifulSoup
import csv
main_url = 'https://cubingchina.com'
def get_html(url):
'''
根据url返回相应的html对象
'''
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}
response = requests.get(url, headers=headers)
response.encoding='utf-8'
html = response.text
# print(response)
return html
def get_soup(html):
'''
根据HTML返回beautifulsoup对象
'''
soup = BeautifulSoup(html, 'lxml')
return soup
def get_rank_list(soup):
'''
使用beautifulsoup解析网页,取得选手信息
返回选手信息列表
'''
rank_text_list = soup.find('table', {'class': 'table table-bordered table-condensed table-hover table-boxed'})
rank_text_list = rank_text_list.find_all('tr')[1:]
rank_list = []
for rank_text in rank_text_list:
rank_text = rank_text.find_all('td')
rank = rank_text[1].extract().text
name = rank_text[2].extract().text
result = rank_text[4].extract().text
competitive = rank_text[5].extract().text
date = rank_text[6].extract().text
item = (rank, name, result, competitive, date)
rank_list.append(item)
return rank_list
def writer_file(rank_list, flag=''):
'''
写入csv文件
'''
header = ('排名', '姓名', '成绩', '比赛', '日期')
with open('333_single_China.csv', 'a', encoding='utf-8', newline='') as file:
writer = csv.writer(file)
if flag == 'first':
writer.writerow(header)
for rank in rank_list:
writer.writerow(rank)
def get_next_url(soup):
'''
获取下一页地址
'''
url_text = soup.find('li', {'class': 'next'})
url_text = url_text.find('a')
url = main_url + url_text.get('href')
return url
def main():
start_url = 'https://cubingchina.com/results/rankings'
html = get_html(start_url)
soup = get_soup(html)
# print(soup)
# 排名写入文件
rank_list = get_rank_list(soup)
# print(rank_list)
writer_file(rank_list, 'first')
print('第1页下载完成')
# 获取下一页url
next_url = get_next_url(soup)
# 获取最后一页url
last_text = soup.find('li', {'class': 'last'})
last_text = last_text.find('a')
last_url = main_url + last_text.get('href')
i = 2
while next_url != last_url:
html = get_html(next_url)
soup = get_soup(html)
rank_list = get_rank_list(soup)
writer_file(rank_list)
next_url = get_next_url(soup)
print('第{}页下载完成'.format(i))
i += 1
# 下载获取最后一页
html = get_html(next_url)
soup = get_soup(html)
rank_list = get_rank_list(soup)
writer_file(rank_list)
print('第{}页下载完成'.format(i))
if __name__=="__main__":
main()
新手上路,很多不成熟和错误的地方请各位谅解
感谢观看!