数据采集与融合技术-第二次实践作业
作业1
要求:在中国气象网(http://www.weather.com.cn)给定城市集的 7日天气预报,并保存在数据库
Gitee链接 |
---|
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo1.py |
from bs4 import BeautifulSoup
from bs4 import UnicodeDammit
import urllib.request
import sqlite3
# 定义一个处理数据库的类
class WeatherDB:
def openDB(self):
# 连接到SQLite数据库文件weathers.db,如果文件不存在则会自动创建
self.con=sqlite3.connect("weathers.db")
# 创建一个游标对象用于执行SQL命令
self.cursor=self.con.cursor()
try:
# 尝试创建一个weathers表,如果表已存在则忽略
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):
# 向weathers表插入一条天气记录
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):
# 查询并打印weathers表中的所有记录
self.cursor.execute("select * from weathers")
rows = self.cursor.fetchall()
for row in rows:
# 格式化打印每条记录
print("%-16s%-16s%-32s%-16s%-16s" % (row[0], row[1], row[2], row[3], row[4]))
# 定义一个用于获取和处理天气数据的类
class WeatherForecast:
def __init__(self):
# 设置HTTP请求头,模拟浏览器访问
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}
# 定义城市代码映射
self.cityCode = {"北京": "101010100", "上海": "101020100", "广州": "101280101", "深圳": "101280601"}
def forecastCity(self, city):
# 构造城市天气页面的URL
url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"
try:
# 创建HTTP请求对象
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
# 使用BeautifulSoup解析HTML
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
if not li.select('p[class="tem"] span'):
temp=li.select('p[class="tem"] i')[0].text
else :
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):
# 初始化WeatherDB对象
self.db = WeatherDB()
self.db.openDB()
# 遍历城市列表,获取每个城市的天气信息
for city in cities:
self.forecastCity(city)
# 关闭数据库连接
self.db.closeDB()
# 创建WeatherForecast对象
ws = WeatherForecast()
# 处理指定城市的天气信息
ws.process(["北京", "上海", "广州", "深圳"])
# 打印完成信息
print("completed")
结果
心得体会
在开发这个天气信息抓取和存储的小项目时,我学习到了几个重要的概念和技巧:
HTTP请求
通过urllib.request
模块,我学会了如何发送HTTP请求来获取网页数据。设置合适的请求头来模拟浏览器行为,以便更好地与服务器进行交互。
HTML解析
使用BeautifulSoup
库,我掌握了如何解析HTML文档。这让我能够从复杂的网页结构中提取出我想要的数据。
字符编码处理
通过UnicodeDammit
类,我学会了如何处理不同编码的网页内容,确保数据能够正确地被解析和显示。
数据库操作
使用sqlite3
模块,我了解了如何在Python中操作SQLite数据库,包括创建表、插入数据和查询数据。
作业2
要求: 用 requests 和 BeautifulSoup 库方法定向爬取股票相关信息,并存储在数据库中。
Gitee链接 |
---|
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo2.py |
import requests
import re
import pandas as pd
import sqlite3
# 初始化一个空列表,用于存储解析后的数据
data = []
# 定义API的URL
url = 'https://76.push2.eastmoney.com/api/qt/clist/get?cb=jQuery11240586371080087019_1728982019591&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&dect=1&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=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1728982019595'
# 发送GET请求到API
res = requests.get(url)
# 设置响应的编码为utf-8,确保中文字符能够正确显示
res.encoding = 'utf-8'
# 初始化一个空列表,用于存储解析后的每一行数据
result = []
# 获取响应的文本内容
data = res.text
# 定义正则表达式模式,用于匹配不同的股票数据字段
id_pattern = r'"(f12)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
name_pattern = r'"(f14)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
newPrice_pattren = r'"(f2)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
price_change_amplitude_pattren = r'"(f3)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
price_change_Lines_pattren = r'"(f4)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
volume_pattren = r'"(f5)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
turnover_pattren = r'"(f6)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
amplitude_pattren = r'"(f7)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
highest_pattren = r'"(f15)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
lowest_pattren = r'"(f16)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
today_pattren = r'"(f17)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
yesteday_pattren = r'"(f18)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
# 使用正则表达式提取数据
id = re.findall(id_pattern, data)
name = re.findall(name_pattern, data)
newPrice = re.findall(newPrice_pattren, data)
price_change_amplitude = re.findall(price_change_amplitude_pattren, data)
price_change_Lines = re.findall(price_change_Lines_pattren, data)
volume = re.findall(volume_pattren, data)
turnover = re.findall(turnover_pattren, data)
amplitude = re.findall(amplitude_pattren, data)
highest = re.findall(highest_pattren, data)
lowest = re.findall(lowest_pattren, data)
today = re.findall(today_pattren, data)
yesteday = re.findall(yesteday_pattren, data)
# 遍历提取的数据,将其组织成字典格式,并添加到result列表中
for i in range(len(name)):
result.append({
'代码' : id[i][1],
'名称': name[i][1],
'最新价' : newPrice[i][1],
'涨跌幅' : price_change_amplitude[i][1],
'涨跌额' : price_change_Lines[i][1],
'成交量(手)' : volume[i][1],
'成交额' : turnover[i][1],
'振幅' : amplitude[i][1],
'最高' : highest[i][1],
'最低': lowest[i][1],
'今开' : today[i][1],
'昨收' : yesteday[i][1]
})
# 将result列表转换为Pandas DataFrame
df = pd.DataFrame(result)
# 打印DataFrame
print(df)
# 定义数据库名称
db_name = 'stock_data.db'
# 连接到SQLite数据库
# 如果文件不存在,会自动在当前目录创建
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
# 创建表
# 如果表已经存在,则忽略
cursor.execute('''
CREATE TABLE IF NOT EXISTS stock_info (
code TEXT,
name TEXT,
new_price TEXT,
price_change_amplitude TEXT,
price_change_lines TEXT,
volume TEXT,
turnover TEXT,
amplitude TEXT,
highest TEXT,
lowest TEXT,
today TEXT,
yesterday TEXT
)
''')
# 插入数据
for item in result:
cursor.execute('''
INSERT INTO stock_info (code, name, new_price, price_change_amplitude, price_change_lines, volume, turnover, amplitude, highest, lowest, today, yesterday)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (item['代码'], item['名称'], item['最新价'], item['涨跌幅'], item['涨跌额'], item['成交量(手)'], item['成交额'], item['振幅'], item['最高'], item['最低'], item['今开'], item['昨收']))
# 提交事务
conn.commit()
# 关闭连接
cursor.close()
conn.close()
结果
心得体会
自动化与效率
通过编写脚本来自动化数据获取和处理流程,可以显著提高工作效率。这不仅减少了重复性工作,还允许我们有更多的时间来分析数据和做出决策。
数据清洗的重要性
在数据分析之前,数据清洗是一个重要的步骤。它可以确保数据的质量和分析结果的准确性。不准确的数据会导致错误的结论,因此这一步骤不容忽视。
正则表达式的威力
正则表达式是一个非常强大的工具,它可以用来进行复杂的文本搜索、替换和提取。然而,它也需要仔细设计模式以避免错误。掌握正则表达式可以大大提升处理字符串数据的能力。
数据库操作的重要性
学习如何与数据库交互是处理数据的关键技能。它允许我们存储、查询和分析大量数据。了解SQL语言和数据库设计原则是必不可少的。
作业3
要求: 爬取中国大学 2021 主榜(https://www.shanghairanking.cn/rankings/bcur/2021)所有院校信息,并存储在数据库中,同时将浏览器 F12 调试分析的过程录制 Gif 加入至博客中。
Gitee链接 |
---|
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo3.py |
import re
import requests
from bs4 import BeautifulSoup, UnicodeDammit
import pandas as pd
import sqlite3
# 定义一个类,用于管理与SQLite数据库的交互
class schoolDB:
def openDB(self):
# 连接到SQLite数据库,并设置文本工厂为字符串,以避免将字符串转换为数字
self.con = sqlite3.connect("school.db")
self.con.text_factory = str
self.cursor = self.con.cursor()
try:
# 创建一个新表,如果表已存在则忽略
self.cursor.execute('create table schoolInfo (rank int, univNameCn varchar(10), province varchar(10),univCategory varchar(10),score decimal)')
except Exception as err:
# 如果创建表时出现错误,打印错误信息
print(err)
def closeDB(self):
# 提交事务并关闭数据库连接
self.con.commit()
self.con.close()
def insertDB(self, rank, univNameCn, province, univCategory, score):
try:
# 向数据库插入一条新记录
self.cursor.execute('insert into schoolInfo values(?,?,?,?,?)', (rank, univNameCn, province, univCategory, score))
except Exception as err:
# 如果插入数据时出现错误,打印错误信息
print(err)
def showDB(self):
# 查询并打印数据库中的所有记录
self.cursor.execute('select * from schoolInfo')
rows = self.cursor.fetchall()
print(rows)
for row in rows:
print('%-32d%-32s%-32s%-32s%-32f' % (row[0], row[1], row[2], row[3], row[4]))
# 定义一个列表,用于存储省份和学校类型的映射关系
table = ['', 'false', 'null', 0, "理工", "综合", 'true', "师范", "双一流", "211", "江苏", "985", "农业", "山东", "河南", "河北", "北京", "辽宁", "陕西", "四川", "广东", "湖北", "湖南", "浙江", "安徽", "江西", "黑龙江", "吉林", "上海", "福建", "山西", "云南", "广西", 2, "贵州", "甘肃", "内蒙古", "重庆", "天津", "新疆"]
results = []
# 定义要请求的URL
url = "https://www.shanghairanking.cn/_nuxt/static/1728872418/rankings/bcur/2021/payload.js"
res = requests.get(url)
data = res.text
dammit = UnicodeDammit(data,['utf-8'])
data = dammit.unicode_markup
# 定义正则表达式模式,用于匹配不同的数据字段
univNameCn_pattern = 'univNameCn:\s*"([\u4e00-\u9fa5]+)"'
province_pattern = 'province:\s*([a-z])'
univCategory_pattern = 'univCategory:\s*([a-z])'
score_pattern = 'score:\s*([0-9]+(?:\.[0-9]+)?|[a-zA-Z]+)'
# 使用正则表达式提取数据
univNameCn = re.findall(univNameCn_pattern, data)
province = re.findall(province_pattern, data)
univCategory = re.findall(univCategory_pattern, data)
score = re.findall(score_pattern, data)
# 创建数据库实例并打开数据库
myDb = schoolDB()
myDb.openDB()
# 遍历提取的数据,将其组织成字典格式,并添加到results列表中
for i in range(50):
rank = i + 1
n = univNameCn[i]
p = table[ord(province[i]) - 97]
c = table[ord(univCategory[i]) - 97]
s = score[i]
myDb.insertDB(rank, n, p, c, s)
results.append({
'排名': rank,
'学校名称': n,
'省市': p,
'学校类型': c,
'总分': s
})
# 将results列表转换为Pandas DataFrame
df = pd.DataFrame(results)
print(df)
# 显示数据库中的所有记录
myDb.showDB()
# 关闭数据库连接
myDb.closeDB()
结果
心得体会
理解数据源的重要性
在开始编码之前,深入理解数据源的结构和内容至关重要。这有助于我们选择合适的方法来提取和解析数据。在本项目中,通过分析js代码结构,我们使用正则表达式成功提取了所需数据,这体现了对数据源深入理解的重要性。