Python爬虫实战:爬取2023中国最好学科排名

一、实战

1.对中科网网站进行Ajax分析

这里我用的是Egde浏览器,对豆瓣电影top250网站进行检查,可以在网络部分看到该页数据的请求头信息

需要注意的是,我们要爬取的页面数据文件是newly_released这个文件,判断需要从哪个包中提取数据可以在响应里看到:

  1. import requests

  2. # 发请求测试

  3. response = requests.get('【软科排名】-中国最好学科排名|最权威的大学学科|高校学科排名 (shanghairanking.cn)')

  4. 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')

 三、执行爬虫,效果

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值