案例需求:
- 采集“2023中国最好学科排名”的排名分类信息
- 包含的信息有序号,一级分类名称,二级分类名称,2023年学校排名,2022年学校排名,层次比例,logo图片地址,学校名称,总分
- 采集的数据存储在csv表格中,只使用xpath查找
- 每科排名仅获取一页
主页面
子页面
前置条件
使用到的库:
import time
import requests
from lxml import etree
import pandas as pd
from requests.exceptions import RequestException
获取请求:
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
print('请求成功', response.status_code)
content = response.content.decode('utf-8')
else:
print('请求失败', response.status_code)
except RequestException as e:
print('请求失败', e)
except Exception as e:
print('未知错误', e)
设置字典来存储数据:
data = {
'序号': [],
'一级分类': [],
'二级分类': [],
'2023年排名': [],
'2022年排名': [],
'层次水平': [],
'logo': [],
'大学名称': [],
'总分': []
}
案例分析:
使用F12打开检查,找到我们需要获取的数据,各个学科的一级分类和二级分类。我们根据其中的标签寻找规律,我们会发现各个学科中
的标签id是一级分类的id,结合这一点我们首先获取一级分类的id和标题。
subject_first_title = html.xpath('//div[@class="subject-title"]/text()')
subject_number = html.xpath('//span[@class="subject-code"]/text()')
然后利用枚举和循环,遍历各个一级分类并获取它们的二级分类的id和标题。
for i, item in enumerate(subject_first_title, start=1):
subject_second_number = html.xpath(f'//div[@id="{i:02d}"]//a[@class="subj-link"]/span[1]/text()')
subject_second_title = html.xpath(f'//div[@id="{i:02d}"]//a[@class="subj-link"]/span[2]/text()')
获取了主页面中的一级分类id和标题,二级分类id和标题。此时我们需要跳转到二级分类各个标题中的页面去获取学科的学校排名
通过观察我们可以发现,每个网页url的后缀都是各个二级分类的id,利用这一点我们可以嵌套一个循环,使用zip函数将二级分类id和标题拼接起来(标题后续要用),获取各个网页的url以及html信息
for item1, item2 in zip(subject_second_number, subject_second_title):
url_second = f'https://www.shanghairanking.cn/rankings/bcsr/2023/{item1}'
time.sleep(3)
res = requests.get(url_second, headers=headers)
content_second = res.content.decode('utf-8')
html_second = etree.HTML(content_second)
如图,我们使用xpath获取子界面我们想要的数据
由于部分数据获取以后,会有多余的换行符和空格,我们使用lambda表达式对其格式化
# 2023年排名
rank_2023_old = html_second.xpath('//*[@id="content-box"]/div/table/tbody/tr/td[1]/div/text()')
rank_2023 = [text.replace('\n', '').replace(' ', '') for text in rank_2023_old if text is not None]
# 2022年排名
rank_2022 = html_second.xpath('//tr/td/span/text()')
# 层次水平
level_old = html_second.xpath('//*[@id="content-box"]/div/table/tbody/tr/td[3]/text()')
level = [text.replace('\n', '').replace(' ', '') for text in level_old if text is not None]
# 图片地址
logo = html_second.xpath('//tr/td/div/div/img/@src')
# 大学名称
unversity_name_old = html_second.xpath('//div/span[@class="name-cn"]/text()')
unversity_name = [text.replace('\n', '').replace(' ', '') for text in unversity_name_old if text is not None]
# 总分
total_score_old = html_second.xpath('//*[@id="content-box"]/div/table/tbody/tr/td[5]/text()')
total_score = [text.replace('\n', '').replace(' ', '') for text in total_score_old if text is not None]
遍历各个数据的列表向字典中添加数据
for rank_2023_item, rank_2022_item, level_item, logo_item, unversity_name_item, total_score_item in zip(rank_2023, rank_2022, level, logo, unversity_name, total_score):
data['序号'].append(num)
data['一级分类'].append(item)
data['二级分类'].append(item1+item2)
data['2023年排名'].append(rank_2023_item)
data['2022年排名'].append(rank_2022_item)
data['层次水平'].append(level_item)
data['logo'].append(logo_item)
data['大学名称'].append(unversity_name_item)
data['总分'].append(total_score_item)
print(num)
num += 1
最后通过使用pandas库对数据进行存储,保存为csv表格中
df = pd.DataFrame(data)
df.to_csv('scholar_best_subject.csv', index=False, encoding='utf-8-sig')
结果展示:
学习总结
本案例旨在通过一级分类中包含不同数量的二级分类并获取各个二级分类中各个学科的学校排名信息,让我们在学会如何处理多级数据分类提取的逻辑,以及提高我们对处理各个数据之间异同的敏感性