在数据驱动的世界中,网络抓取(Web Scraping)是获取和分析互联网数据的重要工具。本文将展示一个使用 Python 进行网络抓取的实际案例——从某大学排名网站提取数据并将其保存为 CSV 文件。
项目概述
在这个示例中,我们从一个大学排名网站上抓取了有关大学排名的详细信息。我们将重点介绍以下步骤:
- 抓取主页面数据:提取所有学科的标题和子标题。
- 提取详细页面数据:从每个子页面提取大学的排名信息。
- 保存数据:将抓取到的数据保存为 CSV 文件,便于进一步分析。
代码实现
1. 抓取主页面数据
首先,我们需要抓取主页面以获取所有学科的基本信息。这些信息包括主标题和子标题的 URL。
import requests
from lxml import html
import time
# 基础 URL
base_url = "https://www.shanghairanking.cn/rankings/bcsr/2023"
def fetch_subjects_list():
session = requests.Session()
retry = 3
while retry > 0:
try:
response = session.get(base_url, timeout=10)
response.raise_for_status()
tree = html.fromstring(response.content)
subjects = []
subject_items = tree.xpath('//div[@class="subject-item"]')
for subject in subject_items:
main_code = subject.xpath('.//span[@class="subject-code"]/text()')[0].strip()
main_title = subject.xpath('.//div[@class="subject-title"]/text()')[0].strip()
main_full_title = f'{main_code}{main_title}'
sub_items = subject.xpath('.//div[@class="subject-list"]//a')
for item in sub_items:
sub_code = item.xpath('.//span[1]/text()')[0].strip()
sub_title = item.xpath('.//span[2]/text()')[0].strip()
sub_full_title = f'{sub_code}{sub_title}'
sub_url = f"{base_url}/{sub_code}"
subjects.append({
'main_full_title': main_full_title,
'sub_full_title': sub_full_title,
'sub_url': sub_url
})
return subjects
except requests.RequestException as e:
print(f"Error fetching main page: {e}")
retry -= 1
time.sleep(5) # 等待5秒后重试
raise Exception("Failed to fetch the main page after multiple attempts.")
2. 提取详细页面数据
接下来,我们需要从每个子页面提取详细的大学排名数据。我们将提取的信息包括大学名称、2023年排名、2022年排名、Logo链接以及总分等。
def extract_data_from_details_page(details_html_content):
tree = html.fromstring(details_html_content)
rows = tree.xpath('//tr')
data = []
for row in rows:
try:
ranking_2023 = row.xpath('.//td/div[@class="ranking"]/text()')
ranking_2022 = row.xpath('.//td/span[@data-v-6c038bb7=""]/text()')
overall_rank = row.xpath('.//td[contains(text(), "前")]/text()')
univ_name = row.xpath('.//td//span[@class="name-cn"]/text()')
logo_url = row.xpath('.//td//div[@class="logo"]/img/@src')
total_score = row.xpath('.//td[last()]/text()') # 更新 XPath 以提取总分
if not univ_name:
continue
data.append({
'2023年排名': ranking_2023[0].strip() if ranking_2023 else 'N/A',
'2022年排名': ranking_2022[0].strip() if ranking_2022 else 'N/A',
'全部层次': overall_rank[0].strip() if overall_rank else 'N/A',
'大学名称': univ_name[0].strip() if univ_name else 'N/A',
'Logo链接': logo_url[0].strip() if logo_url else 'N/A',
'总分': total_score[0].strip() if total_score else 'N/A'
})
except Exception as e:
print(f"Error extracting data from row: {e}")
continue
return data
3. 保存数据至 CSV 文件
最后,我们将提取的数据保存为 CSV 文件,以便后续的分析和使用。
import csv
def save_to_csv(data):
with open('detailed_subjects.csv', 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = ['序号', '一级分类', '二级分类', '2023年排名', '2022年排名', '全部层次', '大学名称', 'Logo链接', '总分']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for index, row in enumerate(data, start=1):
row['序号'] = index
writer.writerow(row)
print("数据已成功保存到 detailed_subjects.csv")
4. 主程序
主程序协调以上步骤,抓取数据并保存至 CSV 文件。
def main():
all_data = []
subjects = fetch_subjects_list()
for subject in subjects:
sub_title = subject['sub_full_title']
sub_url = subject['sub_url']
print(f"Fetching data from: {sub_url}")
session = requests.Session()
retry = 3
while retry > 0:
try:
response = session.get(sub_url, timeout=10)
response.raise_for_status()
details_html_content = response.content
# 提取数据
university_data = extract_data_from_details_page(details_html_content)
for data in university_data:
full_data = {
'一级分类': subject['main_full_title'],
'二级分类': subject['sub_full_title'],
**data
}
all_data.append(full_data)
break # 如果成功,跳出重试循环
except requests.RequestException as e:
print(f"Error fetching details page {sub_url}: {e}")
retry -= 1
time.sleep(5) # 等待5秒后重试
else:
print(f"Failed to fetch data for {sub_url} after multiple attempts")
# 保存数据到 CSV
save_to_csv(all_data)
if __name__ == "__main__":
main()
总结
通过以上步骤,我们成功地从一个大学排名网站抓取了数据并将其保存到 CSV 文件中。这种方法可以灵活地应用于各种数据抓取任务,为数据分析提供了可靠的数据来源。希望这个示例对你有帮助,也期待你在实际应用中根据需要做出调整和优化。