1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
#!/usr/bin/python # -*- coding: utf-8 -*- import json # 快速導入此模塊:鼠標先點到要導入的函數處,再Alt + Enter進行選擇 from multiprocessing.pool import Pool #引入進程池 import requests import re import csv from requests.exceptions import RequestException #引入異常 ## 正確保存,無丟失 # 請求一個頁面返回響應內容 #以《霸王別姬》為列,右擊—查看元素—會顯示一個網頁信息 def get_one_page(url,offset): try : response = requests.get(url = url,params = { "offset" :offset}) if response.status_code = = 200 : #由狀態碼判斷返回結果,200表示請求成功,300,500表出錯 return response.text #返回網頁內容 else : return None except RequestException as e: return None # 解析一個頁面 def parse_one_page(html): pattern = ( '<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a' + '.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>' + '.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>' ) #寫個正則,匹配所有結果。這里由上面的網頁相應內容寫<dd>開頭,.*?匹配任意字符穿 board-index匹配標識符,類名, # \d 表數字即排名,'+'表示匹配至少一個可多個數字,</i>右邊結束符 #“?”,問號表示 非貪婪匹配,就是一旦匹配到就不在繼續往后面嘗試。 #而\(和\)分別表示匹配一個“(”和“)” # re.S匹配多行 regex = re. compile (pattern,re.S) #一個方法,通過一個正則表達式字符串編譯生成一個正則表達式對象,re.S 匹配任意字符 items = regex.findall(html) #以列表形式返回全部能匹配的子串. eg: re.findall(pattern, string[, flags]) for item in items: #將結果以字典形式返回,鍵值對 yield { #把這個方法變成一個生成器 'index' :item[ 0 ], 'image' :item[ 1 ], 'title' :item[ 2 ], 'actor' :item[ 3 ].strip()[ 3 :], #用strip()去掉換行符,不想要 主演: 這三個字就用[3:]組成一個切片,name就可以將前三個字符串去掉 'time' :get_release_time(item[ 4 ].strip()[ 5 :]), #去掉前五個字符 'area' :get_release_area(item[ 4 ].strip()[ 5 :]), 'score' :item[ 5 ] + item[ 6 ] #將評分整數部分和小數部分結合起來 } ''''' #保存到txt,會發現中文漢字變成了unic的編碼,加上encoding='utf-8',ensure_ascii=False,則漢字可正常輸出 def write_to_file(content): with open('result.txt','a',encoding='utf-8') as f: # 參數 a ,表示直接往后追加 f.write(json.dumps(content,ensure_ascii=False) +'\n') #content是一個字典的形式,用json.dumps 把它轉換為字符串,再加個換行符 f.close() #json.dumps :dict 轉換為 str #json.loads: str 轉換為 dict ''' '''''' '' # 獲取上映時間 <p class="releasetime">上映時間:1993-01-01(中國香港)</p> def get_release_time(data): pattern = '^(.*?)(\(|$)' regex = re. compile (pattern) w = regex.search(data) return w.group( 1 ) # group(1)指的是第一個括號里的東西 # 獲取上映地區 def get_release_area(data): pattern = '.*\((.*)\)' #而\(和\)分別表示匹配一個 '(' 和 ')' regex = re. compile (pattern) w = regex.search(data) if w is None : return '未知' return w.group( 1 ) # 獲取封面大圖,不需要 # def get_large_thumb(url): # pattern = '(.*?)@.*?' # regex = re.compile(pattern) # w = regex.search(url) # return w.group(1) # 存儲數據 def store_data(item): with open ( 'movie.csv' , 'a' ,newline = ' ',encoding=' utf - 8 ') as data_csv: # dialect為打開csv文件的方式,默認是excel,delimiter="\t"參數指寫入的時候的分隔符 csv_writer = csv.writer(data_csv) csv_writer.writerow([item[ 'index' ], item[ 'image' ], item[ 'title' ], item[ 'actor' ],item[ 'time' ],item[ 'area' ],item[ 'score' ]]) # 參數newline是用來控制文本模式之下,一行的結束字符??梢允荖one,'',\n,\r,\r\n等。 ''''' 也可判斷異常,一般沒錯 try: csv_writer = csv.writer(data_csv) csv_writer.writerow([item['index'], item['image'], item['title'], item['actor'],item['time'],item['area'],item['score']]) except Exception as e: print(e) print(item) ''' # 下載封面圖 #讀方式打開的話,并不會新建;寫方式打開的話就會新建。 r只讀,w可寫,a追加 def download_thumb(title,image): try : response = requests.get(image) # 獲取二進制數據 with open ( 'image/' + title + '.jpg' , 'wb' ) as f: #將封面圖保存到當前路徑下的image文件夾中,圖片名稱為:電影名.jpg f.write(response.content) f.close() except RequestException as e: print (e) pass # 主調度程序 def main(): # 起始URL start_url = 'http://maoyan.com/board/4?' for i in range ( 0 , 1000 , 10 ): # 獲取響應文本內容 html = get_one_page(url = start_url, offset = i) if html is None : print ( '鏈接:%s?offset=%s異常' . format (start_url,i)) continue for item in parse_one_page(html): # print(item) store_data(item) # download_thumb(item['title'],item['image']) # if __name__ = = '__main__' : main() ''''' if __name__=='__main__': for i in range(10): main(i*10) ''' ''''' if __name__=='__main__': for i in range(10): main(i*10) pool=Pool() #可以提供指定數量的進程供用戶調用,如果有一個新的請求被提交到進程池,進程池還沒有滿,就會創建新的進程來執行請求,如果滿了,就先等待 pool.map(main,[i*10 for i in range(10)]) #將數組中的每一個元素拿出來當做函數的參數,然后創建一個個的進程,放到進程池里面去運行;第二個參數是構造一個數組,組成循環 #速度明顯變快!1s ''' |
保存到數據庫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
def main(offset): url = 'http://maoyan.com/board/4?offset=' + str (offset) html = get_one_page(url) # for item in parse_one_page(html): # print(item['number']) #能正確輸出 , charset="utf8" try : conn = pymysql.connect(host = 'localhost' , user = 'root' , passwd = ' ' , port = 3306 ,db = 'test1' ,charset = "utf8" ,use_unicode = False ) cur = conn.cursor() # 創建一個游標對象 for item in parse_one_page(html): try : # sql = "INSERT INTO movies (number,picture,title,actors,time,area,score) VALUES (%s,%s,%s,%s,%s,%s,%s)" # cur.execute(sql, ( item['number'],item['picture'],item['title'],item['actors'],item['time'],item['area'],item['score'])) sql = "insert into test_movies (number,picture,title,actors,time,area,score) values(%s,%s,%s,%s,%s,%s,%s)" cur.execute(sql, (item[ 'number' ], item[ 'picture' ], item[ 'title' ], item[ 'actors' ], item[ 'time' ], item[ 'area' ],item[ 'score' ])) except pymysql.Error as e: print (e) print ( '- - - - - 數據保存成功 - - - - -' ) conn.commit() cur.close() conn.close() # 關閉數據 except pymysql.Error as e: print ( "Mysql Error %d: %s" % (e.args[ 0 ], e.args[ 1 ])) if __name__ = = '__main__' : # 連接數據庫 conn = pymysql.connect(host = 'localhost' , user = 'root' , passwd = ' ' , port = 3306 , db = 'test1' , charset = "utf8" ) cur = conn.cursor() # 創建一個游標對象 cur.execute( "DROP TABLE IF EXISTS test_movies" ) # 如果表存在則刪除 # 創建表sql語句 sqlc = """CREATE TABLE test_movies( number int not null primary key auto_increment, picture VARCHAR(100) NOT NULL, title VARCHAR(100) NOT NULL, actors VARCHAR(200) NOT NULL, time VARCHAR(100) NOT NULL, area VARCHAR(100) , score VARCHAR(50) NOT NULL )""" cur.execute(sqlc) # 執行創建數據表操作 pool = Pool() pool. map (main,[i * 10 for i in range ( 10 )]) |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/sisteryaya/article/details/77899539