read_html函數(shù)是最簡單的爬蟲池颈,可爬取靜態(tài)網頁表格數(shù)據(jù),但只適合于爬取table 表格型數(shù)據(jù)钓丰,不是所有表格都可以用read_html爬取饶辙,有的網站表面上看起來是表格,但在網頁源代碼中不是table格式斑粱,而是list列表格式弃揽,這種表格就不適用read_html爬取。
pymysql庫可以將Python與SQL數(shù)據(jù)庫建立完美連接,而read_sql在pymysql庫建立連接后將SQL數(shù)據(jù)庫的數(shù)據(jù)讀取進來矿微,整個流程如下:read_html抓取網頁數(shù)據(jù)?pymysql庫建立連接存儲數(shù)據(jù)?read_sql讀取數(shù)據(jù)庫中的數(shù)痕慢,下面一起來操作一下。
1. read_html抓取數(shù)據(jù)
下面先學習一下read_html() 函數(shù)的參數(shù)涌矢,在代碼行中寫入
import pandas as pd
df=pd.read_html()
在括號中使用Shift+Tab組合鍵調用代碼提示功能掖举,可以看到read_html都包含以下參數(shù)。
這里例舉常用的一些參數(shù)娜庇。
io:url塔次、html文本、本地文件等
header:標題行
flavor:解析器
skiprows:跳過的行
attrs:屬性名秀,例如:attrs = {'id':'table'}
parse_dates:解析日期
下面我們使用代碼實際爬取網頁表格數(shù)據(jù)励负,比如下面的新浪財經數(shù)據(jù)中心。
在該數(shù)據(jù)中心界面右鍵點擊檢查匕得。
查找元素的時候我們發(fā)現(xiàn)新浪財經數(shù)據(jù)中心的數(shù)據(jù)即為表格型數(shù)據(jù)继榆,如下圖所示在檢查元素里面有table的字樣。
檢查發(fā)現(xiàn)上面的數(shù)據(jù)為表格型數(shù)據(jù)汁掠,使用read_html爬取網頁數(shù)據(jù)略吨,返回的結果是DataFrame組成的list ,在最后加上一個索引[0]即可得到爬取的表格數(shù)據(jù)考阱。
import pandas as pd
df=pd.read_html('http://vip.stock.finance.sina.com.cn/q/go.php/vComStockHold/kind/jjzc/index.phtml')[0]
df.head()
下拉到網頁的最后翠忠,發(fā)現(xiàn)該數(shù)據(jù)中心包含多個頁面,點擊下一頁即可看到乞榨。
點擊到第二頁负间,發(fā)現(xiàn)網頁網址的后綴變?yōu)?p=2。
點擊到第三頁姜凄,發(fā)現(xiàn)網頁網址的后綴變?yōu)?p=3政溃。
看到這里我們是不是發(fā)現(xiàn)了規(guī)律,就是每次點擊下一頁态秧,對應的頁面后面的網址會跟著變化董虱,下面我們構造一個list,用于存儲各個頁碼下的網址申鱼,比如我們爬取前6頁網頁表格數(shù)據(jù)愤诱。
url_str='http://vip.stock.finance.sina.com.cn/q/go.php/vComStockHold/kind/jjzc/index.phtml?p='foriinrange(6):url=str(url_str)+str(i+1)print(url)
構造好網址鏈接后,使用for循環(huán)遍歷出來捐友,依次使用read_html將數(shù)據(jù)爬取下來淫半,并用concat函數(shù)將表格數(shù)據(jù)全部合并起來。
importpandasaspddf=pd.DataFrame()url_str='http://vip.stock.finance.sina.com.cn/q/go.php/vComStockHold/kind/jjzc/index.phtml?p='foriinrange(6):url=str(url_str)+str(i+1)#print(url)df=pd.concat([df,pd.read_html(url)[0]])print('網站第{}頁.....抓取完成'.format(i+1))df.head()
如下就是我們數(shù)據(jù)爬取的結果匣砖,將新浪財經數(shù)據(jù)中心的每一頁表格數(shù)據(jù)抓取下來科吭。
2. pymysql建立連接
將數(shù)據(jù)導入數(shù)據(jù)庫昏滴,這里還是使用上面的數(shù)據(jù)文件,連接數(shù)據(jù)庫使用的模塊為pymysql对人。
#導入需要使用到的數(shù)據(jù)模塊
import pymysql
數(shù)據(jù)庫連接谣殊,host為數(shù)據(jù)庫地址、user為用戶名牺弄、password為密碼姻几、db為數(shù)據(jù)庫的名字、port為端口势告,默認為3306蛇捌。
# 建立數(shù)據(jù)庫連接
con = pymysql.connect(host='127.0.0.1',
? ? ? ? ? ? ? ? ? ? ? user='root',
? ? ? ? ? ? ? ? ? ? ? password='123456',
? ? ? ? ? ? ? ? ? ? ? db='demo',
? ? ? ? ? ? ? ? ? ? ? port=3306)
獲取游標對象。
# 獲取游標對象
cursor = con.cursor()
用數(shù)據(jù)庫demo咱台,'USE demo' 也是數(shù)據(jù)庫內的SQL語言络拌。
#使用數(shù)據(jù)庫demo
cursor.execute('USE demo')
構造一個test_table表,包含代碼吵护、簡稱、截至日期等多個字段表鳍,執(zhí)行代碼命令后馅而,在Navicat里面刷新即可看到如下的一張空表。
#創(chuàng)建一個SQL表
cursor.execute('create table if not exists test_table(代碼 char(10) primary key,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 簡稱 char(10),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 截至日期 char(10),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 家數(shù) int(10),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 本期持股數(shù) float,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 持股占已流通A股比例 float,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 同上期增減 float,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 持股比例 float,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 上期家數(shù) int(10))')
關于創(chuàng)建一張空表譬圣,下面的SQL語法等同于上面的Python生成一張空的表瓮恭。
CREATE TABLE `test_table` (
? ? ? ? ? ? ? ? ? ? ? ? ? ? `代碼` char(10) NOT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `簡稱` char(10) DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `截至日期` char(10) DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `家數(shù)` int(10) DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `本期持股數(shù)` float DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `持股占已流通A股比例` float DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `同上期增減` float DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `持股比例` float DEFAULT NULL,
? ? ? ? ? ? ? ? ? ? ? ? ? ? `上期家數(shù)` int(10) DEFAULT NULL,
? ? PRIMARY KEY (`代碼`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
接著向test_table表內插入從網頁爬取的數(shù)據(jù)。
#插入數(shù)據(jù)語句
query = "insert into test_table(代碼,簡稱,截至日期,家數(shù),本期持股數(shù),持股占已流通A股比例,同上期增減,持股比例,上期家數(shù))
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? values (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
迭代讀取每行數(shù)據(jù)厘熟,轉化數(shù)據(jù)類型屯蹦,將其保存在values內。
#迭代讀取每行數(shù)據(jù)绳姨,values中元素有個類型的強制轉換登澜,否則會出錯
for r in range(0, len(df)):
? ? ? ? 代碼 = df.iloc[r,0]
? ? ? ? 簡稱 = df.iloc[r,1]
? ? ? ? 截至日期=df.iloc[r,2]
? ? ? ? 家數(shù)=df.iloc[r,3]
? ? ? ? 本期持股數(shù)=df.iloc[r,4]
? ? ? ? 持股占已流通A股比例=df.iloc[r,5]
? ? ? ? 同上期增減=df.iloc[r,6]
? ? ? ? 持股比例=df.iloc[r,7]
? ? ? ? 上期家數(shù)=df.iloc[r,8]
? ? ? ? values = (代碼,簡稱,截至日期,家數(shù),本期持股數(shù),持股占已流通A股比例,同上期增減,持股比例,上期家數(shù))
? ? ? ? #print(values)
cursor.execute(query, values)
關閉游標,提交飘庄,關閉數(shù)據(jù)庫連接脑蠕,在Navicat里面刷新即可看到已經存儲到本地數(shù)據(jù)庫中的數(shù)據(jù)。
#關閉游標跪削,提交谴仙,關閉數(shù)據(jù)庫連接,如果沒有這些關閉操作,執(zhí)行后在數(shù)據(jù)庫中查看不到數(shù)據(jù)
cursor.close()
con.commit()
con.close()
3. read_sql數(shù)據(jù)庫查詢
利用Python從數(shù)據(jù)庫查詢數(shù)據(jù)只需要兩步碾盐,第一步使用pymysql庫將Python與數(shù)據(jù)庫進行連接晃跺,第二步使用read_sql命令將數(shù)據(jù)庫數(shù)據(jù)讀取進來。
#導入需要使用到的數(shù)據(jù)模塊
import pymysql
import pandas
# 建立數(shù)據(jù)庫連接
con = pymysql.connect(host='127.0.0.1',
? ? ? ? ? ? ? ? ? ? ? user='root',
? ? ? ? ? ? ? ? ? ? ? password='123456',
? ? ? ? ? ? ? ? ? ? ? db='demo',
? ? ? ? ? ? ? ? ? ? ? port=3306)
read_sql函數(shù)中有個sql參數(shù)用于使用SQL語法查詢數(shù)據(jù)毫玖,數(shù)據(jù)查詢后的結果如下掀虎。
#SQL語句查詢
sql='select * from test_table'
df_sql=pd.read_sql(sql,con)
df_sql.head()