数据采集与融合第二次作业
这个作业属于哪个课程 | 2024数据采集与融合班级 |
---|---|
本次作业的码云 | fufubuff_python爬虫实践作业3 |
这次作业的链接 | 数据采集与融合第二次作业 |
学号姓名 | 102202141黄昕怡 |
作业内容概述
在本次作业中,我完成了以下三个任务:
- 作业①:从中国气象网(http://www.weather.com.cn)爬取指定城市的7日天气预报,并将数据保存至数据库。
- 作业②:使用
requests
和BeautifulSoup
库定向爬取股票相关信息,并存储在数据库中。 - 作业③:爬取中国大学2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)的所有院校信息,并将数据保存至数据库,同时录制并展示浏览器F12调试过程的Gif。
以下是各项作业的详细实现过程和心得体会。
作业一:爬取中国气象网7日天气预报
作业要求
实现代码
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 语句输出当前操作的信息和错误提示,帮助我及时发现和解决问题。这种调试方式在实际开发中非常实用。
总结:
在爬取过程中,遇到了网页结构变化和动态内容加载的挑战。通过不断调试和优化选择器,最终成功提取了所需的数据。这让我认识到,网页结构的多变性和复杂性是爬虫开发中常见的问题,必须具备灵活应对的能力。
本次作业虽然实现了基本的功能,但在数据抓取效率和错误处理方面还有提升空间。未来可以考虑引入多线程或异步编程,提高爬取速度;同时,优化异常处理机制,增强程序的鲁棒性。
通过这次作业,我不仅掌握了基本的网页爬取技术和数据库操作,还提升了代码设计和问题解决的能力。这些技能将在我未来的数据处理和分析工作中发挥重要作用。同时,这次实践也让我意识到,理论知识与实际应用相结合的重要性,只有通过不断实践,才能更好地掌握和运用所学知识。
作业二:爬取股票相关信息
作业要求
实现代码
# 用 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 的 requests
、re
和 pandas
库,爬取了中国大学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编程语言的理解,还提升了我在实际应用中解决问题的能力。以下是我在完成这三个作业过程中所获得的主要收获和体会:
-
掌握网页爬取技术:通过爬取中国气象网和东方财富网的数据,我熟练掌握了使用
requests
和BeautifulSoup
库进行网页数据抓取的基本方法。同时,通过分析目标网站的结构和API接口,我学会了如何高效地提取所需信息,避免了复杂的HTML解析。 -
处理动态内容和API数据:在爬取中国大学2021主榜时,我学会了如何通过分析网页的API请求,直接获取结构化的JSON数据。这不仅提高了数据抓取的效率,还让我理解了如何绕过动态加载内容,获取更为准确和全面的数据。
-
数据存储与管理:通过使用SQLite数据库,我学会了如何设计数据库表结构、进行数据插入和查询操作。这使得我能够将爬取到的数据进行系统化的存储和管理,为后续的数据分析和展示奠定了基础。
-
正则表达式的应用:在处理API返回的数据时,正则表达式成为了我提取关键数据的重要工具。虽然正则表达式相对复杂,但在需要从混淆或编码的数据中提取信息时,它展现了强大的威力。
-
数据处理与分析:通过使用
pandas
库,我能够轻松地对爬取到的数据进行整理、清洗和导出。这不仅提高了数据处理的效率,也为数据的进一步分析和可视化提供了便利。 -
错误处理与调试能力:在爬取和处理数据的过程中,难免会遇到各种问题,如网络请求失败、数据缺失或格式不符。通过不断地调试和优化代码,我提升了自己解决问题和应对挑战的能力。
-
代码结构与模块化设计:为了提高代码的可读性和维护性,我学习了如何将不同功能模块化,编写结构清晰、注释详细的代码。这不仅有助于团队合作,也为未来的项目开发打下了坚实的基础。
-
项目管理与时间规划:完成三个作业需要合理的时间管理和任务规划。这让我认识到在实际项目中,良好的时间管理和任务分配是确保项目顺利完成的重要因素。
总体而言,本次作业让我在实际操作中巩固了所学的编程知识,并通过解决实际问题提升了自己的技术能力。这些经验不仅为我未来的学习和工作提供了宝贵的支持,也激发了我对数据科学和自动化技术的浓厚兴趣。接下来,我计划进一步深入学习更高级的爬取技术,如使用 Scrapy
框架、处理复杂的动态网页以及进行多线程或异步爬取,以提升数据抓取的效率和覆盖范围。