一、实战
1.对中科网网站进行Ajax分析
这里我用的是Egde浏览器,对豆瓣电影top250网站进行检查,可以在网络部分看到该页数据的请求头信息
需要注意的是,我们要爬取的页面数据文件是newly_released这个文件,判断需要从哪个包中提取数据可以在响应里看到:
-
import requests
-
# 发请求测试
-
response = requests.get('【软科排名】-中国最好学科排名|最权威的大学学科|高校学科排名 (shanghairanking.cn)')
-
print(response)
2.提取数据
利用Xpath方法提取Xpath路径
二、python完整代码
1.导入相关模块
import logging import os import requests from lxml import etree import pandas as pd from fake_useragent import UserAgent from requests import RequestException import time
2.定义获取html地址函数
def get_html(url, headers): """ 发送请求并获取网页内容 该函数对给定的URL发送GET请求,携带指定的请求头, 并返回网页的内容。如果请求失败或超时,将返回None并打印错误信息。 参数: - url: 字符串,要请求的URL - headers: 字典,请求中要携带的请求头 返回: - 字符串,网页的内容(如果请求成功) - None,如果请求失败或超时 """ try: # 发送GET请求,设置超时时间为3秒 resp = requests.get(url, headers=headers, timeout=3) # 检查响应状态码 if resp.status_code == 200: return resp.content.decode('utf-8') else: # 如果获取页面失败,记录错误日志并返回 None logging.error(f"获取页面失败,状态码: {resp.status_code}") return None except RequestException as e: # 如果发生请求异常,记录错误日志并返回None logging.error(f"请求出错: {e}") return None except Exception as e: # 打印发生的错误信息 print(f"请求过程中发生错误:{e}") return None
3.解析html数据
def parse_html(html): """ 解析HTML并提取所需的数据 该函数主要用于解析给定的HTML内容,提取其中的大标题、小标题、图片地址和简介内容,并将这些信息以字典的形式返回 """ # 初始化数据字典,用于存储解析出来的数据 data = {"序号": [], "一级分类": [], "二级分类": [], "2023排名": [], "2022排名": [], "层次比例": [], "logo图片地址": [], "学校名称": [], "总分": []} # 使用etree.HTML解析HTML内容 htmlEles = etree.HTML(html) # 获取一级分类名称 first_categories = htmlEles.xpath('//div[@class="subject-title"]/text()') #获取一级分类名称对应的序号 first_categories_number = htmlEles.xpath('//span[@class="subject-code"]/text()') # 初始化序号,用于生成连续的序号 number = 1 for i, item in enumerate(first_categories, start=1): second_categories_number = htmlEles.xpath(f'//div[@id="{i:02d}"]//a[@class="subj-link"]/span[1]/text()') second_categories = htmlEles.xpath(f'//div[@id="{i:02d}"]//a[@class="subj-link"]/span[2]/text()') if second_categories is None: continue for j, second_item in zip(second_categories_number, second_categories): url_2 = f'https://www.shanghairanking.cn/rankings/bcsr/2023/{j}' time.sleep(1) res = requests.get(url_2, headers=headers) content_2 = res.content.decode('utf-8') html_2 = etree.HTML(content_2) # 2023年排名 rank_2023_old = html_2.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_2.xpath('//tr/td/span/text()') # 层次水平 level_old = html_2.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_2.xpath('//tr/td/div/div/img/@src') # 大学名称 unversity_name_old = html_2.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_2.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(number) data['一级分类'].append(item) data['二级分类'].append(j + second_item) 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) number += 1 return data
3.存储到csv文件中 ,如果文件不存在则创建文件
def save_to_csv(data, filename): df = pd.DataFrame(data) # 检查文件是否存在 if os.path.exists(filename): # 文件存在 if os.path.getsize(filename) == 0: # 文件存在但为空 df.to_csv(filename, index=False, encoding='utf-8-sig') print(f"数据已保存到 {filename} 文件") else: # 文件存在且非空 # 读取现有的CSV文件 existing_data = pd.read_csv(filename) # 合并现有数据和新数据,忽略旧的索引 combined_data = pd.concat([existing_data, pd.DataFrame(data)], ignore_index=True) # 去重,保留电影中文名称不重复的记录 unique_data= combined_data.drop_duplicates(subset=['序号'], keep='first') unique_data.to_csv(filename, index=False, encoding='utf-8-sig') print(f"数据已保存到 {filename} 文件") else: # 文件不存在 df.to_csv(filename, index=False, encoding='utf-8-sig') print(f"数据已保存到 {filename} 文件")
4.函数进行调用整个函数
if __name__ == '__main__': # 定义请求URL和请求头 url = "https://www.shanghairanking.cn/rankings/bcsr/2023" headers = { "User-Agent": UserAgent().random } html = get_html(url, headers) if html: data = parse_html(html) save_to_csv(data, '2023_ranking.csv')
三、执行爬虫,效果