資料採集與融合技術作業2

102202133zqj發表於2024-10-26

Gitee作業連結:https://gitee.com/zheng-qijian33/crawl_project/tree/master/作業2

作業①

要求:在中國氣象網(http://www.weather.com.cn)給定城市集的7日天氣預報,並儲存在資料庫

程式碼

import requests
import sqlite3
from bs4 import BeautifulSoup
import logging

# 配置日誌記錄
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 獲取指定城市的天氣資料
def fetch_weather_data(city_code):
    base_url = 'http://www.weather.com.cn/weather/'
    full_url = f'{base_url}{city_code}.shtml'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.3.5211 SLBChan/112'
    }
    try:
        response = requests.get(full_url, headers=headers)
        response.raise_for_status()
        response.encoding = 'utf-8'
        soup = BeautifulSoup(response.text, 'html.parser')

        weather_forecast = []
        forecast_list = soup.find('ul', class_='t clearfix').find_all('li')

        for day in forecast_list:
            date = day.find('h1').text.strip()
            weather = day.find('p', class_='wea').text.strip()
            temp_high = day.find('span').text.strip() if day.find('span') else ''
            temp_low = day.find('i').text.strip()
            temp = f"{temp_high}/{temp_low}"
            weather_forecast.append((date, weather, temp))

        return weather_forecast

    except requests.RequestException as e:
        logging.error(f"Error fetching weather data for city code {city_code}: {e}")
        return []

# 建立資料庫和表
def setup_database():
    conn = sqlite3.connect('weathers.db')
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS weather_forecast (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            city TEXT,
            date TEXT,
            weather TEXT,
            temperature TEXT
        )
    ''')
    conn.commit()
    return conn

# 儲存天氣資料到資料庫
def save_weather_data(city, weather_data, conn):
    cursor = conn.cursor()
    for date, weather, temp in weather_data:
        cursor.execute("INSERT INTO weather_forecast (city, date, weather, temperature) VALUES (?, ?, ?, ?)",
                       (city, date, weather, temp))
    conn.commit()

# 顯示資料庫中的天氣資料
def display_weather_data(conn):
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM weather_forecast")
    rows = cursor.fetchall()

    print(f"{'序號':<5} {'地區':<10} {'日期':<15} {'天氣資訊':<20} {'溫度':<15}")
    for row in rows:
        print(f"{row[0]:<5} {row[1]:<10} {row[2]:<15} {row[3]:<20} {row[4]:<15}")

def main():
    # 定義城市和對應的程式碼
    city_codes = {
        '北京': '101010100',
        '上海': '101020100',
        '福州': '101230101',
        '天津': '101030100'
    }

    # 建立資料庫連線
    conn = setup_database()

    # 獲取並儲存每個城市的天氣資料
    for city, city_code in city_codes.items():
        weather_data = fetch_weather_data(city_code)
        if weather_data:
            save_weather_data(city, weather_data, conn)
        else:
            logging.warning(f"No weather data for city {city}")

    # 顯示資料庫中的天氣資料
    display_weather_data(conn)

    conn.close()

if __name__ == '__main__':
    main()

執行結果

心得體會

編寫這段天氣資料抓取和儲存的程式碼讓我深刻體會到,良好的程式設計實踐如模組化設計、錯誤處理、日誌記錄和資料驗證對於構建健壯、可維護的應用程式至關重要。模組化設計使得程式碼更易於理解和擴充套件;錯誤處理確保了程式在面對異常情況時能夠優雅地響應;日誌記錄為監控和除錯提供了寶貴的資訊;資料驗證則保障了資料的準確性和完整性。

作業②

要求:用requests和BeautifulSoup庫方法定向爬取股票相關資訊,並儲存在資料庫中。

程式碼

import requests
import re
import sqlite3

# 用get方法訪問伺服器並提取頁面資料
def getHtml(page,cmd):
    url = ("http://66.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112409097606620255823_1696662149317&pn=1&pz=20&po=1&np="+str(page)+
           "&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=|0|0|0|web&"+cmd+
           "&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&_=1696662149318")
    r = requests.get(url)
    pat = "\"diff\":\\[(.*?)\\]"
    data = re.compile(pat, re.S).findall(r.text)
    return data

def getOnePageStock(cmd, page):
    # 提供的JSON陣列
    data = getHtml(page,cmd)
    datas = data[0].split("},")
    #分解每條股票

    # 連線到SQLite資料庫(如果不存在,則會建立一個新的資料庫檔案)
    conn = sqlite3.connect('stock_data.db')
    cursor = conn.cursor()

    # 建立股票資訊表
    cursor.execute('''CREATE TABLE IF NOT EXISTS stock_info (
                        id INTEGER PRIMARY KEY,
                        stock_code TEXT,
                        stock_name TEXT,
                        stock_price REAL,
                        price_change REAL,
                        price_change_percent REAL,
                        volume INTEGER,
                        turnover REAL,
                        amplitude REAL,
                        highest REAL,
                        lowest REAL,
                        open_price REAL,
                        last_close REAL
                    )''')


    # 解析JSON陣列並將資料儲存到資料庫中
    for item in datas:
        # 使用字串操作來提取鍵值對
        stock_info = {}
        pairs = item.split(',')
        for pair in pairs:
            key, value = pair.split(':')
            key = key.strip('"')
            value = value.strip('"')
            stock_info[key] = value

        # 提取需要的欄位
        stock_code = stock_info.get('f12', 'N/A')
        stock_name = stock_info.get('f14', 'N/A')
        stock_price = float(stock_info.get('f2', 0.0))
        price_change_percent = float(stock_info.get('f3', 0.0))
        price_change = float(stock_info.get('f4', 0.0))
        volume = int(stock_info.get('f5', 0))
        turnover = float(stock_info.get('f6', 0.0))
        amplitude = float(stock_info.get('f7', 0.0))
        highest = float(stock_info.get('f15', 0.0))
        lowest = float(stock_info.get('f16', 0.0))
        open_price = float(stock_info.get('f17', 0.0))
        last_close = float(stock_info.get('f18', 0.0))

        # 插入資料到資料庫中
        cursor.execute(
            "INSERT INTO stock_info (stock_code, stock_name, stock_price, price_change_percent, price_change, volume, turnover, amplitude, highest, lowest, open_price, last_close) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (stock_code, stock_name, stock_price, price_change_percent, price_change, volume, turnover, amplitude, highest,
             lowest, open_price, last_close))

        conn.commit()

    # 查詢股票資訊
    cursor.execute("SELECT * FROM stock_info")

    # 獲取查詢結果
    stocks = cursor.fetchall()

    # 獲取查詢結果的列名
    columns = [desc[0] for desc in cursor.description]

    # 列印列標籤
    print("\t".join(columns))

    # 列印股票資訊
    for stock in stocks:
        # 列印每行資料
        print("\t".join(map(str, stock)))

    # 關閉資料庫連線
    conn.close()

page = 1

getOnePageStock("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", page)

執行結果

心得體會

在編寫這段程式碼的過程中,我深刻體會到了網路資料抓取和解析的複雜性與挑戰性。首先,透過使用谷歌瀏覽器的F12除錯工具,我學會了如何監控網路請求,識別出股票資料載入時使用的具體API端點。這一步對於理解資料來源和結構至關重要。
分析API返回的JSON資料讓我意識到,資料的結構化和非結構化部分需要仔細處理。透過使用正規表示式和字串操作,我能夠提取出所需的關鍵資訊,並將其組織成適合儲存和查詢的格式。
在編寫程式碼時,我意識到請求引數的選擇對於獲取正確的資料至關重要。透過調整URL中的引數,如f1和f2,我能夠控制返回的資料範圍和內容。這種靈活性使我能夠根據需求定製資料抓取任務,提高了效率和準確性。

作業③

要求:爬取中國大學2021主榜(https://www.shanghairanking.cn/rankings/bcur/2021)所有院校資訊,並儲存在資料庫中,同時將瀏覽器F12除錯分析的過程錄製Gif加入至部落格中。

程式碼

import urllib.request
from bs4 import BeautifulSoup
import sqlite3

# 目標網頁URL
your_url = 'https://www.shanghairanking.cn/rankings/bcur/2021'   

# 使用 urllib 開啟網頁
response = urllib.request.urlopen(your_url)
html = response.read()

# 使用 BeautifulSoup 解析網頁
soup = BeautifulSoup(html, 'html.parser')

# 定位到包含大學排名資訊的部分
table = soup.find('table', {'class': 'rk-table'})

# 連線到SQLite資料庫(如果資料庫不存在則建立)
conn = sqlite3.connect('schools_rank.db')
cursor = conn.cursor()

# 建立表(如果尚未建立)
cursor.execute('''CREATE TABLE IF NOT EXISTS university_ranking
                    (rank TEXT, school_name TEXT, province_city TEXT, school_type TEXT, total_score TEXT)''')

# 遍歷表格中的每一行
for row in table.find_all('tr')[1:]:   # 跳過表頭
    cols = row.find_all('td')
    rank = cols[0].text.strip()
    school_name = cols[1].text.strip()
    province_city = cols[2].text.strip()
    school_type = cols[3].text.strip()
    total_score = cols[4].text.strip()

    # 插入資料到資料庫
    cursor.execute('''INSERT INTO university_ranking (rank, school_name, province_city, school_type, total_score)
                       VALUES (?, ?, ?, ?, ?)''', (rank, school_name, province_city, school_type, total_score))

# 提交事務
conn.commit()

# 查詢資料庫並列印所有記錄
cursor.execute("SELECT * FROM university_ranking")
all_records = cursor.fetchall()
for record in all_records:
    # 移除字串中的換行符
    cleaned_record = tuple(field.replace('\n', '') for field in record)

    # 列印清理後的記錄
    print(cleaned_record)

# 關閉資料庫連線
conn.close()

print("大學排名資料已儲存到資料庫")

執行結果

瀏覽器F12除錯分析的過程錄製Gif

心得體會

編寫這段程式碼的過程中,我深刻體會到了網路資料抓取和解析的複雜性與挑戰性。首先,透過分析目標網站的網路請求,我學會了如何識別和理解網站載入資料時使用的API端點。這一步對於理解資料的來源和結構至關重要。

在分析API返回的資料時,我意識到資料的結構化和非結構化部分需要仔細處理。透過使用BeautifulSoup庫,我能夠解析HTML內容並提取出所需的關鍵資訊,如大學排名、學校名稱、所在城市、學校型別和總分。

將資料儲存到SQLite資料庫中的過程讓我認識到了資料持久化的重要性。透過建立表和插入資料,我確保了抓取到的資訊可以被長期儲存和查詢,這對於後續的資料分析和應用是非常有用的。

相關文章