擼主聽說有個網站叫他趣,里面有個社區,其中有一項叫他趣girl,擼主點進去看了下,還真不錯啊,圖文並茂,宅男們自己去看看就知道啦~
接下來當然就是爬取這些妹子的圖片啦,不僅僅是圖片,擼主發現里面的對話也很有意思,於是把對話也一並抓取下來好了。
那么問題來了,用什么工具呢?在之前的練習中已經用過urllib2,正則表達式匹配實在麻煩,這次來點稍微高級的,試試selenium;
selenium是什么?其實它是一個web自動化測試的工具,運行起來就跟我們自己操作瀏覽器差不多,廢話不多說,下面開始。
工具:python2.7 + selenium2 python版
1 首先導入需要的模塊,然后定義本地存放目錄
1 # coding: utf-8 2 3 from selenium import webdriver 4 from selenium.common.exceptions import NoSuchElementException 5 from time import * 6 import os 7 import urllib2 8 9 # 文件保存路徑 10 file_path = r'F:\taqu'
2 然后還是定義3個函數,分別用來為每個girl創建目錄,保存每個girl的圖片,保存每個girl的文本描述和對話;其中在保存圖片的時候還是用到了urllib2
# ------------定義3個函數,用來創建每個girl的目錄、保存圖片、寫入文本描述及對話---------------- def mkdir_for_girl(path, name): """ 創建以標題命令的目錄 :param name: 目錄名稱 :return: 返回創建的目錄路徑 """ path = os.path.join(path, name) if not os.path.exists(path): os.mkdir(path) return path def save_pictures(path, url_list): """ 保存圖片到本地指定文件夾 :param path: 保存圖片的文件夾,由mkdir_for_girl返回 :param url_list: 待保存圖片的url列表 :return: none """ for (index, url) in enumerate(url_list): try: print u'%s 正在保存第%d張圖片' % (ctime(), index) pic_name = str(index) + '.jpg' file_name = os.path.join(path, pic_name) # 如果存在該圖片則不保存 if os.path.exists(file_name): print u'%s 該圖片已經存在' % ctime() continue req = urllib2.Request(url, headers={'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'}) data = urllib2.urlopen(req, timeout=30).read() f = open(file_name, 'wb') f.write(data) f.close() except Exception, e: print u'%s 第%d張圖片保存失敗,不處理,跳過繼續處理下一張' % (ctime(), index) def write_text(path, info): """ 在path目錄中創建txt文件,將info信息(girl的文本描述和對話)寫入txt文件中 :param path: 保存txt文件的目錄,由mkdir_for_girl返回 :param info: 要寫入txt的文本內容 :return: none """ # 創建/打開info.txt文件,並寫入內容 filename = os.path.join(path, 'info.txt') with open(filename, 'a+') as fp: fp.write(info.encode('utf-8')) fp.write('\n'.encode('utf-8')) fp.write('\n'.encode('utf-8'))
3 定義webdirver,打開目標網頁,其中切換到目標頁面使用了超鏈接文本定位元素
# -----------------------打開頁面,設置超時時間,窗口最大化----------------------- driver = webdriver.Firefox() driver.implicitly_wait(10) driver.maximize_window() driver.get(r'http://www.taqu.cn/community/') # -----------------------切換到“他趣Girl”頁面----------------------- driver.find_element_by_partial_link_text(u'他趣Girl').click()
4 由於所有girl都在一個頁面中,但是這個頁面很長很長,真的很長,需要滑動很久才能滑到底部,為什么要滑動到底部呢?
因為瀏覽器獲取的HTML源碼,只有當前窗口已顯示元素的代碼,未顯示部分的代碼沒有,當然selenium也定位不到那些元素了;
所以說,如果要selenium能找到所有girl,先要把頁面滑動到底部,等所有girl都加載完,才能獲取到包含所有girl的HTML代碼。
那么問題來了,怎么滑動頁面呢,通過瀏覽器的滾動條,但是滾動條不是HTML元素,selenium不能直接控制,這里就得借助
javascript了,在selenium中執行js代碼還是可以的,具體實現看代碼:
# -----------------------滑動到窗口最底部,以將所有的girl都刷新出來----------------------- # 由於頁面很長,並且需要不斷下拉才會刷新,因此通過javascript來控制器滾動條向下滑動 # 但是一次滑動並不能到達底部,需要多次,那么需要多少次呢?這里采用的方式是不停的向下 # 滑動,每滑動一次,都查詢下是否到達底部,怎么查詢呢?這是通過查到底部的一個標志圖片來判斷, # 如果沒找到標志,就說明還沒到達底部,需要繼續滑動,如果找到就跳出循環
# 為了快速滑動,先設置超時時間為1秒
driver.implicitly_wait(1)
# 不停的滑啊滑 while True: driver.execute_script("window.scrollTo(0,document.body.scrollHeight)") try: # 定位頁面底部的一個圖片 driver.find_element_by_xpath(".//*[@id='waterfall-loading']/img[@src='/img/no-more.png']") # 如果沒拋出異常就說明找到了底部標志,跳出循環 break except NoSuchElementException as e: # 拋出異常說明沒找到底部標志,繼續向下滑動 pass # 將超時時間改回10秒 driver.implicitly_wait(10)
5 獲取到整個完整的頁面后,就可以一次找出所有的girl封面圖片了,這些封面圖片是可以點擊的,一點就打開了該girl的所有圖片和對話,
這里使用的是CSS選擇器,比起xpath,擼主更喜歡CSS一些
# -----------------------找到所有girl的封面圖片----------------------- # 這些封面圖片是可點擊的,單擊都會彈出該girl的所有圖片和文字描述 girls = driver.find_elements_by_css_selector("div#container img") num = len(girls) print u"girl總數為:%d" % num
6 最后一步了,遍歷所有的封面圖片,依次點擊,然后抓取保存每一個girl的圖片和對話,保存到本地
# -----------------------依次點擊每張封面,提取每個girl的信息----------------------- for girl in girls: # 依次點擊每一個girl的封面 girl.click() # 每點擊一個girl后,都再點擊一下彈出框,以更新driver,不然driver中的緩存還是上一個girl的 # 一定要注意這一步啊,擼主當時沒有做這一步,折騰了好久 driver.find_element_by_xpath("html/body/div[3]/div[2]").click() # 提取標題,由於標題中的字符:和|不能作為文件名,將他們替換了 title = driver.find_element_by_css_selector("p.waterfall-detail-header-title").text title = title.encode('utf-8') title = title.replace(":", ":") title = title.replace("|", "丨") title = title.decode('utf-8') # 在file_path目錄下,為該girl創建以標題命名的目錄 path = mkdir_for_girl(file_path, title) # 提取該girl所有圖片的URL pics = driver.find_elements_by_css_selector("div.water-detail-content img") pic_url = [x.get_attribute('src') for x in pics] print u'該girl的圖片總數為:%d' % len(pic_url) # 保存圖片到本地以該girl標題命名的目錄中 save_pictures(path, pic_url) # 提取girl的基本介紹,並寫入info.txt文件 info = driver.find_element_by_xpath("html/body/div[3]/div[2]/div[2]/div[2]").text write_text(path, info) # 提取所有對話,寫入info.txt文件 talks = driver.find_elements_by_css_selector("div.water-detail-content p") for t in talks: write_text(path, t.text) # 關閉該girl的圖片 driver.find_element_by_xpath("html/body/div[3]/div[2]/div[1]/div/img").click() print u'該girl信息提取完成,繼續處理下一個' sleep(1) # -----------------------所有girl信息提取完成----------------------- driver.close() print u'恭喜,所有girl信息提取完成!'
7 試着運行下,看下輸出,是不是有點小激動
girl總數為:90 該girl的圖片總數為:12 Sat May 14 09:24:54 2016 正在保存第0張圖片 Sat May 14 09:24:54 2016 正在保存第1張圖片 Sat May 14 09:24:54 2016 正在保存第2張圖片 。 。省略很多 。 Sat May 14 09:33:36 2016 正在保存第9張圖片 Sat May 14 09:33:37 2016 正在保存第10張圖片 Sat May 14 09:33:37 2016 正在保存第11張圖片 該girl信息提取完成,繼續處理下一個 恭喜,所有girl信息提取完成!
8 再看下本地目錄,是不是很激動?
說明:上面的代碼是完整的,將所有的分段合並在一起就可以運行了。這里可以看到,selenium是很強大的,不僅僅是web自動化工具哦,
還是爬蟲利器呢;但是,但是這里有個缺點就是,selenium會打開瀏覽器UI,這樣操作起來就有點偏慢了,有沒有更好的解決方案呢?---有的!