爬蟲僅爲相互學習,勿做他用!!!
爬蟲部分
爬取數據
爬蟲目標數據
- 各期刊論文的標題、作者、摘要、發表時間等信息
如下:
爬蟲目標網站
目標網站:計算機研究與發展
其中,設我們需要爬取的數據爲該網站 2018 年開始 到至今(2020.1)的所有期刊論文信息,下面看自2018年1月(即2018 第一期)開始的各期論文站點信息:
期號 | 網頁地址 |
---|---|
2018.1 | http://crad.ict.ac.cn/CN/volumn/volumn_1300.shtml |
2018.2 | http://crad.ict.ac.cn/CN/volumn/volumn_1301.shtml |
2018.3 | http://crad.ict.ac.cn/CN/volumn/volumn_1302.shtml |
… | … |
2020.1 | http://crad.ict.ac.cn/CN/volumn/volumn_1327.shtml |
很容易我們就可以看出來,自2018.1開始,期刊地址中的字符串片段"volumn_1300"尾的數字隨月份增加而增加,且一月對一期(共12*12+1 = 25期)。
故而,爬蟲目標網址規律:http://crad.ict.ac.cn/CN/volumn/volumn_ + str(遞增數字) + .shtml
獲取各期刊網址函數如下:
def getUrls():
all_items = 12*2+1
urls = []
partstr = "http://crad.ict.ac.cn/CN/volumn/volumn_"
for i in range(all_items+1):
strone = partstr + str(1300+i) + ".shtml"
urls.append(strone)
for url in urls:
yield url
爬蟲網站頁面元素分析
我們需要的是各期刊論文的標題、作者、摘要、發表時間信息,觀察網站:如下
顯然,我們可以利用 **re(正則表達式)**和 BeautifulSoup庫 輕鬆獲取我們需要的數據:
def parsePage(infoList, html):
soup = BeautifulSoup(html,"html.parser")
item = soup(name='a',attrs={"class":"biaoti"})
biaoti = re.findall(r'target="_blank">(.*?)</a',str(item),re.S)
item = soup(name='dd',attrs={"class":"zuozhe"})
zuozhe = re.findall(r'class="zuozhe">(.*?)</dd',str(item),re.S)
item = soup(name='dd',attrs={"class":"kmnjq"})
fanwei = re.findall(r'class="kmnjq">(.*?)<',str(item),re.S)
fanwei = re.sub('[\r\n\t\xa0]','',''.join(fanwei))
fanwei = re.sub('doi:','',''.join(fanwei))
fanwei = fanwei.split('.')
item = soup(name='div',attrs={"class":"white_content zhaiyao"})
zhaiyao = re.findall(r'">(.*?)</div',str(item),re.S)
for i in range(len(biaoti)):
global count #一個全局變量,用於統計總爬取數據條數
infoList.append((count,biaoti[i],zuozhe[i],fanwei[i],zhaiyao[i]))
count += 1
上述函數中,我們通過正則表達式和 BeautifulSoup庫 獲取數據,並將數據存入 infoList 列表中。
其中,額外需要注意的就是關於發表日期以及所在期刊頁碼信息的處理:
1.如圖:
以上即爲未經處理直接通過正則表達式從 soup 中截取出來的字符串!!
2.處理:
- 去除通過正則表達式從 soup 中截取出來的字符串中重複的
\r\n\t\xa0
- 去除無關字符串
doi
至此,我們需要的數據也已經全部存入 infoList 列表中了!!如下圖:
存儲數據(MySQL)
前置工作
首先,要在 python 中使用 MySQL,需要導入 python 的 pymysql庫:
pymysql庫 的下載:
pip install pymysql
pymysql庫 的導入:
import pymysql
好了,接下來就可以在代碼中連接數據庫並進行插入操作啦!!!
數據庫的設計
根據 infoList 列表存儲的數據:序號 標題 作者 發表時間(期刊,頁碼) 摘要
設計 paperinfo表 來存儲論文信息,如下:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for paperinfo
-- ----------------------------
DROP TABLE IF EXISTS `paperinfo`;
CREATE TABLE `paperinfo` (
`序號` int(0) NOT NULL,
`標題` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`作者` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`年,月,頁碼` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`摘要` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`序號`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
paperinfo表 的主鍵爲 序號 。。
注意存儲摘要使用的數據類型!!!
連接數據庫
通過 connect() 函數連接數據庫,函數內的參數包括 本機地址(host)、端口號(port)、數據庫用戶信息(包括用戶名 user,密碼 password)、連接的數據庫 database、編碼格式 charset 。
cursorclass=pymysql.cursors.DictCursor 是創建默認遊標的意思,可以在連接的時候指定默認遊標,也可以在需要使用時再創建 cursor = connection.cursor()
。
#打開數據庫連接
# localhost等效於127.0.0.1
#注意:這裏之前已經創建了數據庫adnm,database指定了連接的數據庫
def getConnection():
connection = pymysql.connect(
host="localhost",
port=3306,
user="root",
password="123456",
database="adnm",
charset="utf8",
cursorclass=pymysql.cursors.DictCursor
)
return connection
存儲數據
將 infoList 列表插入 paperinfo 表中:
def insertData(infoList):
try:
connection = getConnection()
with connection.cursor() as cursor:
sql = "insert into paperinfo values(%s,%s,%s,%s,%s)"
cursor.executemany(sql,tuple(infoList))
connection.commit()
finally:
connection.close()
注意:
- 爲有效避免因爲錯誤導致的後果,使用
try...catch
語句執行數據庫的插入操作。 - 使用with讀取使用遊標可以省略遊標的關閉(自動關閉)
- 對於sql語句,int(0),varchar(255),text 都通過佔位符 %s 進行佔位預處理操作
- cursor.executemany() 可以同時插入多組數據,如只需插入一組,則使用cursor.execute()
- connection.commit() 執行插入(對於插入、更新、刪除等操作,需要使用connection.commit()來提交到數據庫執行;而查詢、創建數據庫和數據表的操作不需要此語句。)
- 最後,關閉數據庫連接 connection.close()
看看結果:
嘿嘿,是不是還可以呢!!感興趣的小夥伴可以動手試試哦!!
另外,若有問題歡迎各位小夥伴互相交流。。。。
附上源碼:資源