前面講了如何通過pymysql操作數據庫,這次寫一個爬蟲來提取信息,並將數據存儲到mysql數據庫
1.爬取目標
爬取貓眼電影TOP100榜單
要提取的信息包括:電影排名、電影名稱、上映時間、分數
2.分析網頁HTML源碼
可以看到每部電影信息都被包裹在一對<dd>...</dd>標簽中,所以我們只需提取出一個標簽對中的上述信息即可。使用正則表達式提取
3. 完整過程
這個例子有2個關鍵點:正則編寫和數據處理(寫進mysql數據庫)
(1) 正則表達式的編寫
pattern = re.compile(r'<dd>.*?<i.*?>(\d+)</i>.*?' # 匹配電影排名(加個?表示非貪婪匹配,不是匹配0次或1次)
r'<p class="name"><a.*?data-val=".*?">(.*?)' # 匹配電影名稱
r'</a>.*?<p.*?class="releasetime">(.*?)</p>' # 匹配上映時間
r'.*?<i.*?"integer">(.*?)</i>' # 匹配分數的整數位
r'.*?<i.*?"fraction">(.*?)</i>.*?</dd>', re.S) # 匹配分數小數位,re.S表示跨行匹配
m = pattern.findall(html)
# print(m)
使用findall()方法來匹配所有符合規則的字符,返回一個列表,下面是其中一頁的匹配結果
(2)完整代碼,注意get_data()函數是如何處理數據,然后通過write_sql()函數是寫入數據庫的
# coding: utf-8
# author: hmk
import requests
import re
import pymysql
def get_html(url, header):
response = requests.get(url, headers=header)
if response.status_code == 200:
return response.text
else:
return None
def get_data(html, list_data):
pattern = re.compile(r'<dd>.*?<i.*?>(\d+)</i>.*?' # 匹配電影排名
r'<p class="name"><a.*?data-val=".*?">(.*?)' # 匹配電影名稱
r'</a>.*?<p.*?class="releasetime">(.*?)</p>' # 匹配上映時間
r'.*?<i.*?"integer">(.*?)</i>' # 匹配分數的整數位
r'.*?<i.*?"fraction">(.*?)</i>.*?</dd>', re.S) # 匹配分數小數位
m = pattern.findall(html)
for i in m: # 因為匹配到的所有結果會以列表形式返回,每部電影信息以元組形式保存,所以可以迭代處理每組電影信息
ranking = i[0] # 提取一組電影信息中的排名
movie = i[1] # 提取一組電影信息中的名稱
release_time = i[2] # 提取一組電影信息中的上映時間
score = i[3] + i[4] # 提取一組電影信息中的分數,這里把分數的整數部分和小數部分拼在一起
list_data.append([ranking, movie, release_time, score]) # 每提取一組電影信息就放到一個列表中,同時追加到一個大列表里,這樣最后得到的大列表就包含所有電影信息
def write_sql(data):
conn = pymysql.connect(host='localhost',
user='root',
password='123456',
db='test',
charset='utf8')
cur = conn.cursor()
for i in data:
"""這里的data參數是指正則匹配並處理后的列表數據(是一個大列表,包含所有電影信息,每個電影信息都存在各自的一個列表中;
對大列表進行迭代,提取每組電影信息,這樣提取到的每組電影信息都是一個小列表,然后就可以把每組電影信息寫入數據庫了)"""
movie = i # 每組電影信息,這里可以看做是准備插入數據庫的每組電影數據
sql = "insert into maoyan_movie(ranking,movie,release_time,score) values(%s, %s, %s, %s)" # sql插入語句
try:
cur.execute(sql, movie) # 執行sql語句,movie即是指要插入數據庫的數據
conn.commit() # 插入完成后,不要忘記提交操作
print('導入成功')
except:
print('導入失敗')
cur.close() # 關閉游標
conn.close() # 關閉連接
def main():
start_url = 'http://maoyan.com/board/4'
depth = 10 # 爬取深度(翻頁)
header = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, sdch",
"Accept-Language": "zh-CN,zh;q=0.8",
"Cache-Control": "max-age=0",
"Connection": "keep-alive",
"Host": "maoyan.com",
"Referer": "http://maoyan.com/board",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36"}
for i in range(depth):
url = start_url + '?offset=' + str(10 * i)
html = get_html(url, header)
list_data = []
get_data(html, list_data)
write_sql(list_data)
#print(list_data)
# for i in list_data:
# t = i
# print(t)
if __name__ == "__main__":
main()
注意一點,在請求url時,加了headers,這里必須加,估計是網站做了限制,直接爬的話會失敗,可能認出請求鏈接的不是一個人而是一只蟲了
代碼中注釋寫得很詳細,不再過多描述了