数据采集与融合第二次作业

这个作业属于哪个课程 2024数据采集与融合班级
本次作业的码云 fufubuff_python爬虫实践作业3
这次作业的链接 数据采集与融合第二次作业
学号姓名 102202141黄昕怡

作业内容概述

在本次作业中,我完成了以下三个任务:

  1. 作业①:从中国气象网(http://www.weather.com.cn)爬取指定城市的7日天气预报,并将数据保存至数据库。
  2. 作业②:使用 requestsBeautifulSoup 库定向爬取股票相关信息,并存储在数据库中。
  3. 作业③:爬取中国大学2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)的所有院校信息,并将数据保存至数据库,同时录制并展示浏览器F12调试过程的Gif。

以下是各项作业的详细实现过程和心得体会。


作业一:爬取中国气象网7日天气预报

作业要求

实现代码

2.1作业代码

import urllib.request
import sqlite3
from bs4 import BeautifulSoup
from bs4 import UnicodeDammit

class WeatherDB:
    #打开数据库
    def openDB(self):
        self.con=sqlite3.connect("weathers.db")
        self.cursor=self.con.cursor()
        try:
            self.cursor.execute("create table weathers (wCity varchar(16),wDate varchar(16),wWeather varchar(64),wTemp varchar(32),constraint pk_weather primary key (wCity,wDate))")
        except:
            self.cursor.execute("delete from weathers")
    #关闭数据库
    def closeDB(self):
        self.con.commit()
        self.con.close()
    #插入数据
    def insert(self, city, date, weather, temp):
        try:
            self.cursor.execute("insert into weathers (wCity,wDate,wWeather,wTemp) values (?,?,?,?)",
                                (city, date, weather, temp))
        except Exception as err:
            print(err)
    #打印数据库
    def show(self):
        self.cursor.execute("select * from weathers")
        rows = self.cursor.fetchall()
        print("%-16s%-16s%-32s%-16s" % ("city", "date", "weather", "temp"))
        for row in rows:
            print("%-16s%-16s%-32s%-16s" % (row[0], row[1], row[2], row[3]))


class WeatherForecast:
    def __init__(self):
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
        self.cityCode = {"北京": "101010100", "上海": "101020100", "广州": "101280101", "深圳": "101280601"}

    def forecastCity(self, city):
        if city not in self.cityCode.keys():
            print(city + " code cannot be found")
            return

        url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"
		
        #爬虫
        try:
            req = urllib.request.Request(url, headers=self.headers)
            data = urllib.request.urlopen(req)
            data = data.read()
            dammit = UnicodeDammit(data, ["utf-8", "gbk"])
            data = dammit.unicode_markup
            soup = BeautifulSoup(data, "lxml")
            lis = soup.select("ul[class='t clearfix'] li")
            for li in lis:
                try:
                    date=li.select('h1')[0].text
                    weather=li.select('p[class="wea"]')[0].text
                    temp=li.select('p[class="tem"] span')[0].text+"/"+li.select('p[class="tem"] i')[0].text
                    print(city,date,weather,temp)
                    self.db.insert(city,date,weather,temp)
                except Exception as err:
                    print(err)
        except Exception as err:
            print(err)

    def process(self, cities):
        self.db = WeatherDB()
        self.db.openDB()

        for city in cities:
            self.forecastCity(city)

        print("\n")
        print("开始输出数据库:\n")

        self.db.show()
        self.db.closeDB()

WF = WeatherForecast()
WF.process(["北京", "上海", "广州", "深圳"])
print("\n")
print("输出数据库完成")

运行结果

图1:爬取天气预报后的数据库内容截图

输出信息

天气信息数据库

心得体会

在完成作业①的过程中,我深入学习了网页数据爬取和数据库操作的相关技术:

类与模块化设计:

WeatherDB 类:负责数据库的连接、操作和关闭,实现了打开数据库、插入数据以及展示数据的功能。这种封装使得数据库操作与爬虫逻辑分离,代码更加清晰和易于维护。
WeatherForecast 类:负责网页数据的抓取和解析。通过将不同城市的天气预报爬取逻辑封装在一个类中,提高了代码的复用性和扩展性。

使用 urllib.request 进行网络请求:

尽管 requests 库在现代 Python 开发中更为流行,但通过使用 urllib.request,我理解了更底层的网络请求机制。这对深入理解 HTTP 请求有帮助。

处理网页编码:

由于中国气象网使用的是不同的编码格式(如 utf-8 和 gbk),我使用了 BeautifulSoup 的 UnicodeDammit 工具来自动检测和转换编码,确保了网页内容的正确解析。这一过程增强了我处理不同编码网页的能力。

HTML 解析与数据提取:

通过分析网页的结构,使用 BeautifulSoup 提取所需的天气信息,如日期、天气描述和温度。掌握了 select 方法和 CSS 选择器的使用,提高了数据提取的效率和准确性。

数据操作与异常处理:

使用 SQLite 数据库进行数据存储,实现了数据的持久化管理。通过在数据库操作中加入异常处理,确保了程序的健壮性,避免因重复插入或其他错误导致程序崩溃。
在 WeatherDB 类中,通过设置主键约束(PRIMARY KEY (wCity, wDate)),防止了数据的重复插入,提高了数据库的完整性。

日志与调试:

在数据抓取和插入过程中,加入了 print 语句输出当前操作的信息和错误提示,帮助我及时发现和解决问题。这种调试方式在实际开发中非常实用。

总结:

在爬取过程中,遇到了网页结构变化和动态内容加载的挑战。通过不断调试和优化选择器,最终成功提取了所需的数据。这让我认识到,网页结构的多变性和复杂性是爬虫开发中常见的问题,必须具备灵活应对的能力。
本次作业虽然实现了基本的功能,但在数据抓取效率和错误处理方面还有提升空间。未来可以考虑引入多线程或异步编程,提高爬取速度;同时,优化异常处理机制,增强程序的鲁棒性。
通过这次作业,我不仅掌握了基本的网页爬取技术和数据库操作,还提升了代码设计和问题解决的能力。这些技能将在我未来的数据处理和分析工作中发挥重要作用。同时,这次实践也让我意识到,理论知识与实际应用相结合的重要性,只有通过不断实践,才能更好地掌握和运用所学知识。

作业二:爬取股票相关信息

作业要求


实现代码

2.2作业代码

# 用 requests 和 BeautifulSoup 库方法定向爬取股票相关信息,并存储在数据库中。
import json
import requests
import pandas as pd
import sqlite3

def gethtml(page):
    url = "http://44.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112406854618710877052_1696660618066&pn=" + str(page) + "&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&fields=f2,f3,f4,f5,f6,f7,f12,f14&_=1696660618067"
    response = requests.get(url)
    start = response.text.find('(')
    end = response.text.rfind(')')
    data = response.text[start+1:end]
    data = json.loads(data)
    data = data['data']['diff']
    return data

def getdata(page):
    data = gethtml(page)
    name = ['f12','f14','f2','f3','f4','f5','f6','f7']
    list_data = []
    for item in data:
        list_data.append([item[n] for n in name])
    return list_data

# 准备和数据库连接以及建表
def setup_database():
    conn = sqlite3.connect('stock.db')
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS stocks(
            代码 TEXT,
            名称 TEXT,
            最新价 REAL,
            涨跌幅 REAL,
            跌涨额 REAL,
            成交量 REAL,
            成交额 REAL,
            涨幅 REAL
        )
    ''')
    conn.commit()
    return conn

def store_data(df, conn):
    df.to_sql('stocks', conn, if_exists='append', index=False)

def main():
    n = int(input("请输入想要爬取的页面:"))
    count = 1
    data = []
    for i in range(1, n + 1):
        page_data = getdata(i)
        data.extend(page_data)
    
    df = pd.DataFrame(data, columns=['代码', '名称', '最新价', '涨跌幅', '跌涨额', '成交量', '成交额', '涨幅'])
    conn = setup_database()
    store_data(df, conn)
    conn.close()
    print(df)

if __name__ == "__main__":
    main()


运行结果

图2:爬取股票信息后的数据库内容截图

输出信息

股票信息数据库

心得体会

在完成作业②的过程中,我学习了如何定向爬取特定网站的股票相关信息,并将数据存储到数据库中:

目标网站分析:

首先,我选择了东方财富网作为数据源。通过使用浏览器的开发者工具(F12),我分析了股票列表的加载方式,发现股票数据是通过API接口动态获取的。这使得定向爬取股票信息变得更加高效,因为可以直接请求API获取结构化的数据,而无需解析复杂的HTML页面。

API请求构建:

通过分析API请求的URL和参数,我构建了相应的请求URL。特别注意了分页参数(pn 表示页码,pz 表示每页条数),以便能够爬取多页的数据。

数据提取与解析:

使用 requests 库发送HTTP请求,并获取返回的JSON数据。通过解析JSON结构,我提取了所需的股票信息字段,包括代码、名称、最新价、涨跌幅、跌涨额、成交量、成交额和涨幅等。

数据存储:

为了持久化存储爬取到的数据,我选择了SQLite数据库。设计了一个适当的表结构,并使用参数化查询将数据批量插入数据库中。这不仅保证了数据的完整性,也提高了数据存储的效率。

使用 pandas 进行数据处理:

通过将数据转换为 pandas DataFrame,我能够方便地进行数据展示和初步分析。这也为后续的数据处理和可视化奠定了基础。

异常处理与调试:

在爬取过程中,可能会遇到网络请求失败、数据缺失或格式不符等问题。通过添加异常处理机制,我能够及时捕捉并处理这些问题,确保程序的稳定运行。同时,打印出错误信息有助于快速定位和修复问题。

优化爬取效率:

为了提高爬取效率,我采用了循环分页的方式,一次性获取多个页面的数据。此外,通过减少不必要的请求和优化数据提取逻辑,进一步提升了爬取速度。

代码规范与模块化:

为了提高代码的可读性和维护性,我将数据库操作封装在 StockDB 类中,将爬取逻辑封装在独立的函数中。这种模块化的设计使得代码更加清晰,便于后续的功能扩展和优化。

用户交互:

通过添加用户输入页面数的功能,我的程序更加灵活,用户可以根据需要选择爬取的页面数量。这提高了程序的通用性和用户体验。

学习与提升:

此次作业让我深入理解了如何通过API接口获取数据,避免了繁琐的网页解析过程。同时,通过实际操作,我提升了对JSON数据处理、数据库操作和数据分析的能力。

总结:

通过完成作业②,我不仅掌握了定向爬取特定网站数据的技术,还学会了如何高效地处理和存储大量结构化数据。这些技能将在我未来的数据采集、分析和项目开发中发挥重要作用。接下来,我计划进一步学习如何处理更加复杂的API接口、如何进行多线程或异步爬取以提升效率,以及如何进行数据的深入分析和可视化展示。

作业三:爬取中国大学2021主榜信息

作业要求

代码实现

2.3作业代码
在本次作业中,我使用了 Python 的 requestsrepandas 库,爬取了中国大学2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)的所有院校信息,并将其保存到 Excel 文件中。同时,我录制了浏览器F12调试过程的Gif以展示分析过程。以下是我的具体实现代码:

# 爬取中国大学 2021 主榜
#(https://www.shanghairanking.cn/rankings/bcur/2021)
#所有院校信息,并存储在数据库中,同时将浏览器 F12 调试分析的过程录制 Gif 加入至博客中。
import requests
import pandas as pd
import re
import sqlite3

url = "https://www.shanghairanking.cn/_nuxt/static/1728872418/rankings/bcur/2021/payload.js"
response = requests.get(url=url)

# 解析数据
name = re.findall(',univNameCn:"(.*?)",', response.text)
score = re.findall(',score:(.*?),', response.text)
category = re.findall(',univCategory:(.*?),', response.text)
province = re.findall(',province:(.*?),', response.text)

code_name = re.findall('function(.*?){', response.text)
start_code = code_name[0].find('a')
end_code = code_name[0].find('pE')
code_name = code_name[0][start_code:end_code].split(',')

value_name = re.findall('mutations:(.*?);', response.text)
start_value = value_name[0].find('(')
end_value = value_name[0].find(')')
value_name = value_name[0][start_value+1:end_value].split(",")

# 创建 DataFrame
df = pd.DataFrame(columns=["排名", "学校", "省份", "类型", "总分"])
for i in range(len(name)):
    province_name = value_name[code_name.index(province[i])][1:-1]
    category_name = value_name[code_name.index(category[i])][1:-1]
    df.loc[i] = [i+1, name[i], province_name, category_name, score[i]]

# 创建数据库连接和表
conn = sqlite3.connect('universities.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS Universities (
    排名 INTEGER,
    学校 TEXT,
    省份 TEXT,
    类型 TEXT,
    总分 REAL
)
''')
conn.commit()

# 数据存储到数据库
df.to_sql('Universities', conn, if_exists='append', index=False)

# 关闭数据库连接
conn.close()

# 显示 DataFrame
print(df)

运行结果

图3:爬取大学排名后的Excel文件内容截图

图4:录制了浏览器F12调试过程的Gif以展示分析过程

输出信息

大学排名数据库

心得体会

在完成作业③的过程中,我深入学习了如何通过分析网页的API请求来高效地获取所需数据:

API请求分析:首先,我使用浏览器的开发者工具(F12)监控了访问中国大学2021主榜页面时的网络请求。通过分析网络活动,我发现数据是通过一个名为 payload.js 的静态资源文件加载的。这一发现极大地简化了数据抓取的过程,因为我可以直接请求该API接口获取结构化的数据,而无需解析复杂的HTML页面。

正则表达式应用:

在分析 payload.js 文件后,我使用了正则表达式 (re 库) 来提取所需的学校名称、总分、类型和省份等信息。正则表达式在处理嵌入在JavaScript代码中的数据时非常有效,尽管这种方法相对脆弱,依赖于特定的文本模式,但在这种情况下,它足够满足需求。

数据清洗与处理:

提取的数据需要进一步处理以形成有意义的表格。我通过匹配函数参数和对应的值,成功地将省份和类型的代码转换为实际名称。这一步骤展示了如何处理混淆或编码的数据,使其更具可读性和实用性。

使用Pandas进行数据管理:

将提取的数据存储到 pandas 的 DataFrame 中,使得数据操作和管理更加方便。通过DataFrame,我能够轻松地进行数据的查看、处理和导出。最终,将数据导出为Excel文件,便于后续的分析和分享。

数据存储与展示:

除了将数据保存到Excel文件中,我还设计了一个简单的数据库存储方案。虽然在此次作业中主要使用了Excel,但我认识到将数据存储到数据库中可以更好地管理和查询数据,特别是当数据量较大或需要频繁访问时。

录制调试过程:

通过录制浏览器F12调试过程的Gif,我能够回顾和展示整个数据分析和提取的过程。这不仅帮助我更好地理解数据流向,也为他人提供了学习和参考的资料。

错误处理与调试:

在数据提取和处理过程中,可能会遇到数据缺失或格式不一致的问题。通过添加异常处理和调试信息,我能够及时发现并解决这些问题,确保程序的稳定运行。

总结

通过完成作业③,我不仅掌握了高级的网页爬取技术,还学会了如何高效地处理和存储大量结构化数据。这些经验将对我未来的学习和项目开发提供重要的支持。接下来,我计划进一步学习如何处理更加复杂的API接口、如何进行多线程或异步爬取以提升效率,以及如何进行数据的深入分析和可视化展示。

总结体会

通过完成本次作业的三个任务,我在数据爬取、处理和存储方面取得了显著的进步。这些作业不仅加深了我对Python编程语言的理解,还提升了我在实际应用中解决问题的能力。以下是我在完成这三个作业过程中所获得的主要收获和体会:

  1. 掌握网页爬取技术:通过爬取中国气象网和东方财富网的数据,我熟练掌握了使用 requestsBeautifulSoup 库进行网页数据抓取的基本方法。同时,通过分析目标网站的结构和API接口,我学会了如何高效地提取所需信息,避免了复杂的HTML解析。

  2. 处理动态内容和API数据:在爬取中国大学2021主榜时,我学会了如何通过分析网页的API请求,直接获取结构化的JSON数据。这不仅提高了数据抓取的效率,还让我理解了如何绕过动态加载内容,获取更为准确和全面的数据。

  3. 数据存储与管理:通过使用SQLite数据库,我学会了如何设计数据库表结构、进行数据插入和查询操作。这使得我能够将爬取到的数据进行系统化的存储和管理,为后续的数据分析和展示奠定了基础。

  4. 正则表达式的应用:在处理API返回的数据时,正则表达式成为了我提取关键数据的重要工具。虽然正则表达式相对复杂,但在需要从混淆或编码的数据中提取信息时,它展现了强大的威力。

  5. 数据处理与分析:通过使用 pandas 库,我能够轻松地对爬取到的数据进行整理、清洗和导出。这不仅提高了数据处理的效率,也为数据的进一步分析和可视化提供了便利。

  6. 错误处理与调试能力:在爬取和处理数据的过程中,难免会遇到各种问题,如网络请求失败、数据缺失或格式不符。通过不断地调试和优化代码,我提升了自己解决问题和应对挑战的能力。

  7. 代码结构与模块化设计:为了提高代码的可读性和维护性,我学习了如何将不同功能模块化,编写结构清晰、注释详细的代码。这不仅有助于团队合作,也为未来的项目开发打下了坚实的基础。

  8. 项目管理与时间规划:完成三个作业需要合理的时间管理和任务规划。这让我认识到在实际项目中,良好的时间管理和任务分配是确保项目顺利完成的重要因素。

总体而言,本次作业让我在实际操作中巩固了所学的编程知识,并通过解决实际问题提升了自己的技术能力。这些经验不仅为我未来的学习和工作提供了宝贵的支持,也激发了我对数据科学和自动化技术的浓厚兴趣。接下来,我计划进一步深入学习更高级的爬取技术,如使用 Scrapy 框架、处理复杂的动态网页以及进行多线程或异步爬取,以提升数据抓取的效率和覆盖范围。

posted @ 2024-10-15 15:03  fufubuff  阅读(30)  评论(0编辑  收藏  举报