標籤:

python爬取1024某工廠資源

無聊看知乎,發現有一老司機在知乎上開車,利用爬蟲技術能做到哪些很酷很有趣很有用的事情? - 戴笠的回答 - 知乎,作為新司機的我,oh不,學習python新手,這個是一個不錯的練手項目哦,參考了一下老司機的思路,修改了一些代碼開車出發了(網址我就和諧了,我是遵紀守法的好市民)

亮個程序最後完成帶有阻礙人類進步的馬賽克效果圖(如果yellow請務必告訴我刪除)

首先找到這個要爬取的主網址,我就不直接貼了,有興趣的自己去找那老司機線索,直接百度搜索是進不去的。主網址論壇大概像下面論壇排版那樣

對應著帖子標題,帖子裡面就對應著詳細介紹內容,裡面就有張封面圖還有torrent下載跳轉鏈接。現在思路如下,首先把論壇每一頁的每個帖子對應的帖子鏈接get_1024_links(page)爬取下來,然後傳給get_1024_details(url)將帖子裡面的圖跟torrent跳轉鏈接保存取出來,再get_torrent(torrent_link, filename)把跳轉後用表單提交把真正下載地址解析保存到本地。

主要用到的庫是BeautifulSoup,lxml,requests,os,Pool 瀏覽器用火狐UC總之能按F12出現調試都行

老司機前期已經探過雷,了解過網站對爬蟲的保護措施,我也稍微做個筆記介紹一下:

UserAgent_List = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"]def get_request_headers(): request_headers = { User-Agent: random.choice(UserAgent_List), Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", Accept-Encoding: gzip, Cache-Control: no-cache, Upgrade-Insecure-Requests: 1, } return request_headersdef get_torrent_headers(): torrent_headers = { Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8, Accept-Encoding:gzip, deflate, Accept-Language:zh-CN,zh;q=0.8, Cache-Control:max-age=0, Connection:keep-alive, Content-Length:36, Content-Type:application/x-www-form-urlencoded, Cookie:__cfduid=d9130195aadfe9c767b6e27ef36ec8de11482424894; a4184_pages=2; a4184_times=3, Host:www2.馬賽克.info, Origin:http://www2.馬賽克.info, Referer:http://www2.馬賽克.info, Upgrade-Insecure-Requests:1, User-Agent:random.choice(UserAgent_List), } return torrent_headers

(我不會用知乎編輯代碼啊,空格縮進貌似使不出!大家將就點看)

首先,我為此構造了2個headers頭,第一個是用來普通爬取request.get用,第二個是下載跳轉網頁表單提交所用到request.post所用到的。在User-Agent中設置10個,方便headers里User-Agent隨機採用一個。

def IP_Test(IP, URL_test, set_timeout=1) :# 測試IP地址是否可用,時間為3秒 try: requests.get(URL_test, headers=headers, proxies={http: IP}, timeout=set_timeout) return True except: return Falsedef get_IP_test(num_IP=10): IP_url = http://www.youdaili.net/Daili/http/19733.html # 獲取IP的網站 test_url = http://t3.9laik.live/pw/ # 測試IP是否可用的的網站 wb_date = requests.get(IP_url, headers=headers) wb_date.encoding = utf-8 soup = BeautifulSoup(wb_date.text, lxml) IP = soup.select(div.arc > div.content > p > span) IP_list = [] for i in IP: span_IP = i.get_text().encode(utf-8).split(@)[0] print span_IP if IP_Test(span_IP, test_url): # 測試通過 IP_list.append(span_IP) print 測試通過,IP地址為 + str(span_IP) if len(IP_list) > num_IP - 1: # 搜集夠N個IP地址就行了 print(搜集到 + str(len(IP_list)) + 個合格的IP地址) return IP_list return IP_list# for i in get_IP_test():# print iIP_list = [ 118.123.245.206:80, 58.221.75.7:8888, 222.35.74.60:80, 58.68.226.186:80, 175.6.10.12:8888, 58.221.75.145:8888, 210.72.95.134:80, 117.36.73.83:80, 117.34.47.7:8888, 123.234.8.210:8080,]

第二個就是採用不同IP地址去不斷爬取,用了老司機代碼,爬取一個免費IP網站,進行一下文字處理拿出50個IP,把這50個IP地址各自去訪問一下百度,成功就留下保存10個,然後手工放進IP_list列表裡。

好了,現在準備就緒,分析一下網頁

1、用瀏覽器F12。

2、點擊左上角有個小箭頭。

3、點擊隨便一個標題,出現這個標題所在這個網頁HTML的詳細位置。

4、此時這裡出現這個帖子的地址跟標題

5、你只要用滑鼠點擊右鍵,Copy—Copy selector

6、ctrl+F,黏貼上去單獨出現一個,因為每個帖子都是固定格式的,所以這裡篩選需要點修改如圖就會剛剛好找出50個帖子的位置。

def get_1024_links(page): url = http://該板塊鏈接page={}.format(page) url1 = http://主網頁鏈接/pw/ wb_data = requests.get(url) wb_data.encoding = utf-8 # 不然會亂碼,老司機探過這個雷 # print wb_data.text soup = BeautifulSoup(wb_data.text, lxml) # 我習慣用lxml links = soup.select(tr.tr3 > td > h3 > a) links_1024 = [] for link in links: url = url1 + link.get(href) # 拼接成帖子的鏈接 links_1024.append(url) return links_1024 # 返回這一頁50個帖子的鏈接列表

下一步就是進入到帖子裡面了

方法步驟也跟上面差不多,這次要的是圖的位置跟torrent導向鏈接

def get_format_filename(input_filename): # 文件夾的名字不能含有的特殊符號,windows下的限定 for s in [?, *, <, >, , !, :, /]: while s in input_filename: input_filename = input_filename.strip().replace(s, ) return input_filenamedef get_1024_details(url): # 這裡接收get_1024_links返回的link鏈接列表 wb_date = requests.get(url) wb_date.encoding = utf-8 soup = BeautifulSoup(wb_date.text, lxml) #print 子頁面讀取完畢,開始嘗試處理圖片 pic_link = soup.select(#read_tpc > img)[0].get(src) pic = download_single_image(pic_link) # 用的是戴司機的download_single_image函數 if pic != None: filename = soup.select(#subject_tpc)[0].get_text().encode(utf-8) filename = get_format_filename(filename).decode(utf-8) if not os.path.exists(filename):# windows保存文件的坑,不然亂碼 os.makedirs(filename) pic = pic.content # with open(os.getcwd() + //+filename+// +filename + .jpg, wb) as f: # with open(os.getcwd() + // + filename + .jpg, wb) as f: try: with open(os.getcwd() + "//" + filename + "//" + filename + .jpg, wb) as f: f.write(pic) torrent_link = soup.select(#read_tpc > a)[0].get(href) get_torrent(torrent_link, filename) except IOError: print url, filename # 出錯,返回出錯鏈接跟文件名def download_single_image(image_url, proxy_flag=False, try_time=0): # 首先嘗試直接下載,一次不成功則嘗試使用代理 if not proxy_flag:#不使用代理 try: image_html = requests.get(image_url, headers=get_image_header(), timeout=20) print(圖片直接下載成功) time.sleep(1) return image_html #一次就成功下載! except: return download_single_image(image_url, proxy_flag=True)#否則調用自己,使用3次IP代理 else: # 使用代理時 if try_time < count_time: try: print(嘗試第+str(try_time+1)+次使用代理下載) # IP_address=get_random_IP()[0] image_html = requests.get(image_url, headers=get_image_header(), proxies={http: get_random_IP()}, timeout=20) print 狀態碼為+str(image_html.status_code) if image_html.status_code==200: print(圖片通過IP代理處理成功!) return image_html # 代理成功下載! else: a= download_single_image(image_url, proxy_flag=True, try_time=(try_time + 1)) return a except: print(IP代理下載失敗) a = download_single_image(image_url, proxy_flag=True, try_time=(try_time+1)) # 否則調用自己,使用3次IP代理 return a else: print 圖片未能下載 + image_url return None

windows很多編碼坑,一開始保存文件名這裡花了不少時間研究

1、保存文字不能包含?, *, <, >, , !, :, /,否則會出現IOError,有些字元是邊爬取邊出錯,我就列印出出錯文件名,手工新建文件夾看哪個字元不能保存然後加入到get_format_filename()函數中。

2、不encode和decode的話所保存的文件名是亂碼

3、一開始就想爬帖子鏈接時候順便把標題也爬下新建文件夾,但是有些圖是壞鏈接,可能國內IP訪問不了這個原圖吧,像上面的圖那樣,所以我就放到這裡,要爬取到圖片才新建文件夾,名字就是標題,這樣保證裡面都有圖了(實際過程中,有些圖還是壞的)

4、download_single_image下這個圖都是變換著隨機使用代理跟IP,以防被網站封IP

好了,到了結果保存torrent最重要的時候了,卡我最多時間就是這樣了,沒辦法基礎不好

剛才get_1024_details()函數爬取圖片同時還有一個torrent鏈接保存下來,這個鏈接就是進來這個頁面的,還是老方法F12小箭頭放到下載這裡,可以看到這裡有個form裡面有action跟method屬性,帶3個input,這裡就是表單提交了。還有一種方便方法查看:

1、找到Network這裡,這時候滑鼠點擊一下下載,那麼這裡就多出個down.php文件

2、發現請求方法是post(get,post大家看一下requests庫中文文檔)

3、這裡3個就是要秘密post的參數,不同片子的參數不一樣

4、請求Headers就是我們一開始那個get_torrent_headers()函數了,這個就直接把全部複製過來就好了准沒錯。

5、就是萬事俱備給到人家伺服器返回給我們的信息

我們直接把1~4打包好post過去就行了么?不,需要建立一個會話requests.Session()

def get_torrent(torrent_link, filename): torrent_download_url = http://www2.不可描述/down.php s = requests.Session() wb_date = s.get(torrent_link, headers=get_request_headers()) wb_date.encoding = utf-8 soup = BeautifulSoup(wb_date.text, lxml) data = {} for i in soup.select(form input): if i.get(name): data[i.get(name)] = i.get(value) # print data torrent = s.post(torrent_download_url, headers=get_torrent_headers(), data=data) with open(os.getcwd() + //+ filename+// + filename + .torrent, wb+) as f: f.write(torrent.content)

到了這裡,終於完事了,運行程序就是上面一開始圖片結果了!

if __name__ == __main__: pool = Pool(processes=3) for i in range(1,21): print 正在爬起第 + str(i) + 頁 links = get_1024_links(i) try: pool.map(get_1024_details, links) except IndexError: pass pool.close() pool.join()

另外推薦一下這本書,學爬蟲看完這個估計也有個基礎了,當然裡面不是用requests庫而是用urllib2.....

總結一下一些坑和有待完善的地方

坑:

1、網站編碼,Windows保存文件編碼問題

2、保存文件路徑的時候『/』,正反斜杠使用問題

3、requests.post要用會話session連接,還有請求頭

待完善:

1、有些圖不知道是網站原因還是我原因能保存下來但是壞圖打不開

2、出現不可知的錯時候,代碼又要重新爬取之前已經爬過的,當然我可以用mongodb分別保存要下的網址跟已經下好的網址做一個set交集相減處理

3、怎麼能讓程序運行的更快而且又不會被封呢?

希望向各位大神學習學習,有問題請指出,網址我就刪除了,咔咔


推薦閱讀:

零基礎自學 Ruby 或 Python ,除家用電腦外還需哪些硬體和花銷?
第十三章 Python: xml轉json
草根學Python(四) Dict 和 Set
一個通用爬蟲思路(Python3)
pandas可視化(2)【官方文檔解讀】-- 條形圖、直方圖

TAG:Python | 爬蟲 |