<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 模擬瀏覽器來抓
selenium (https
Step1:  找出圖片的網址
Step2:  Q
直接用 urlopen 來找找看圖片網址
有了網址, 可以用 urllib 抓下來。 也可以用 spynner 來抓。
Step3:  如何換頁?
Step4:  開始回圈來抓圖吧
Step5:  已經可以抓了，還有什麼問題？
browser 瀏覽頁面時，已經顯示圖了。之後，又再 download 一次，浪費頻寬。
介面不夠美觀，無法看到進度。
頻寬問題
概念上，有兩個方向。 一是既然 browser 顯示了圖片，表示 browser 有這份圖，我們跟 browser 要就好了。另一個剛好相反，告訴瀏覽器，不要顯示圖片，把圖片的 url 交給我們即可。
這兩個方向各有利弊，以現在這個應用來說，我選擇第二個。原因有三：
QtWebKit 有選項讓你這樣做。 
這樣可行。 browser 仍然會傳回正確的圖片 url。 
可以順便擋住廣告圖片。
Step6:  現在來建立一個介面
Step7:  擋掉更多廣告
Step8:  利用 thread
<ASSISTANT_TASK:>
Python Code:
import spynner
import os, sys
from IPython.display import display, Image
# 用 spynner 打開瀏覽器
browser = spynner.Browser(debug_level=spynner.ERROR, debug_stream=sys.stderr)
browser.show() # 告訴  browser，要它之後不要隱身
# 在 ?????? 填入適當網址
base_url = 'http://v.??????.com/online/comic-7340.html?ch='  
book_no = 54
browser.load( base_url+str(book_no))
Explanation: 模擬瀏覽器來抓
selenium (https://github.com/tjwei/2048-NN/blob/master/my2048-rl-theano-n-tuple-Copy7.ipynb)
PhantomJS http://phantomjs.org/
控制 webkit, pyqt/pygtk/Python-Webkit/ghost.py
spynner (http://weijr-note.blogspot.tw/2014/11/blog-post.html)
Mechanize/MechanicalSoup/RoboBrowser
End of explanation
browser.load_jquery(True)   #  spynner 內建有 jquery，用這個 method 載入，比較方便。
img_url = browser.runjs('$("#TheImg").attr("src")')
print(img_url)
Image(img_url, width=200)
# 當然不用 jquery 也可以
browser.runjs('document.getElementById("TheImg").getAttribute("src")')
Explanation: 找出圖片的網址
End of explanation
img_data = browser.download(img_url) # jpg 檔案內容
with open("cover.jpg", 'wb') as jpg_file:
    jpg_file.write(img_data)
Image(data=img_data, width=200)
Explanation: Q
直接用 urlopen 來找找看圖片網址
有了網址, 可以用 urllib 抓下來。 也可以用 spynner 來抓。
End of explanation
#總共頁數
total_pages = int(browser.runjs('ps'))
total_pages
Explanation: 如何換頁?
End of explanation
for page in range(1, 1+total_pages):
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = browser.runjs('document.getElementById("TheImg").getAttribute("src")')
    print(page, img_url)
    with open("{}-{}.jpg".format(book_no, page), "wb") as f:
        browser.download(img_url, outfd=f)
        print("File saved in", os.getcwd())
Explanation: 開始回圈來抓圖吧
End of explanation
from PySide.QtWebKit import QWebSettings # 用來設定 QtWebKit
# 利用
import ipywidgets as W 
# 設定不自動顯示圖片
settings = browser.webview.settings()
settings.setAttribute(QWebSettings.AutoLoadImages, False)
# 可以看到瀏覽器並不會讀進圖片
total_pages = int(browser.runjs('ps'))
for page in range(1, 1+10):
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = browser.runjs('document.getElementById("TheImg").getAttribute("src")')
    print(page, img_url)
Explanation: 已經可以抓了，還有什麼問題？
browser 瀏覽頁面時，已經顯示圖了。之後，又再 download 一次，浪費頻寬。
介面不夠美觀，無法看到進度。
頻寬問題
概念上，有兩個方向。 一是既然 browser 顯示了圖片，表示 browser 有這份圖，我們跟 browser 要就好了。另一個剛好相反，告訴瀏覽器，不要顯示圖片，把圖片的 url 交給我們即可。
這兩個方向各有利弊，以現在這個應用來說，我選擇第二個。原因有三：
QtWebKit 有選項讓你這樣做。 
這樣可行。 browser 仍然會傳回正確的圖片 url。 
可以順便擋住廣告圖片。
End of explanation
# 建立 Image Widget 用來顯示圖片預覽
img = W.Image()
img.width = 300
# 顯示下載進度的 Progress bar
progress = W.IntProgress(min=1, value=1, max=total_pages)
display(img)
display(progress)
dir_name = os.path.join("download", "{:02d}".format(book_no))
if not os.path.exists(dir_name):
            os.makedirs(dir_name) 
print("Download to {}".format(os.path.join(os.getcwd(), dir_name)))
sys.stdout.flush()
# 開始下載
for page in range(1, total_pages+1):
    # 取得 image url
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = browser.runjs('document.getElementById("TheImg").getAttribute("src")')
    # 下載圖片
    fn = os.path.join(dir_name, "{:03d}.jpg".format(page))
    with open(fn, "wb") as f:
        browser.download(img_url, outfd=f)
    
    # 更新 Widget 的狀態
    progress.description = "%d/%d"%(page, total_pages)
    progress.value = page
    img.value = Image(filename=fn).data
Explanation: 現在來建立一個介面
End of explanation
from PySide.QtNetwork import QNetworkAccessManager, QNetworkRequest # 控制 browser 的網路連線
from PySide.QtCore import QUrl # Qt 的 Url 類別
# 關掉之前的 browser
browser.close()
browser = spynner.Browser(debug_level=spynner.ERROR, debug_stream=sys.stderr)
# 建立一個 webview
# 我們不設定 AutoLoadImages=False, 但增加一些其他設定
# 這裡並不是重點，但適合我們的應用
browser.create_webview()
settings = browser.webview.settings()
# settings.setAttribute(QWebSettings.AutoLoadImages, False)
settings.setAttribute(QWebSettings.JavaEnabled, False)        # 不需要  Java
settings.setAttribute(QWebSettings.DnsPrefetchEnabled, True)  # 試著節省 Dns 花的時間
settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, True) # 不需要瀏覽紀錄
# 建立一個空的  url
BLANK_REQUEST = QNetworkRequest(QUrl())
# 建立一個空的圖片 url
DUMMY_IMG_REQUEST = QNetworkRequest(QUrl("data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="))
# 因為只需要用一次，可以取個又臭又長的名字
class EightComicNetworkAccessManager(QNetworkAccessManager):
    # 只需要取代  createRequest 這個 method 即可 
    def createRequest(self, op, request, device=None):        
        url = str(request.url().toString()) # 參數很多，但只取 url 就夠用        
        if 'comic' not in url[:20]: 
            # 用很醜的方式來判斷非 8comic 網站的 url 
            # 用空的 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, BLANK_REQUEST)
        elif not url.endswith('js') and not url.endswith('css') and '.html' not in url:
            # 凡是  .js .css .html 之外的，都用空的圖片 url  取代原本的 url
            return QNetworkAccessManager.createRequest(self, self.GetOperation, DUMMY_IMG_REQUEST)
        else:
            # 傳回原本的 url
            return QNetworkAccessManager.createRequest(self, op, request, device)
# 設定  browser 的 NetworkAccessManager
browser.webpage.setNetworkAccessManager(EightComicNetworkAccessManager())
browser.show()
browser.load(base_url+str(book_no))
total_pages = int(browser.runjs('ps')) 
%%timeit -n 1 -r 1
# 建立 Image Widget 用來顯示圖片預覽
img = W.Image()
img.width = 300
# 顯示下載進度的 Progress bar
progress = W.IntProgress(min=1, value=1, max=total_pages)
display(img)
display(progress)
dir_name = os.path.join("download", "{:02d}".format(book_no))
if not os.path.exists(dir_name):
            os.makedirs(dir_name) 
print("Download to {}".format(os.path.join(os.getcwd(), dir_name)))
sys.stdout.flush()
# 開始下載
for page in range(1, total_pages+1):
    # 取得 image url
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = browser.runjs('document.getElementById("TheImg").getAttribute("src")')
    # 下載圖片
    fn = os.path.join(dir_name, "{:03d}.jpg".format(page))
    with open(fn, "wb") as f:
        browser.download(img_url, outfd=f)
    
    # 更新 Widget 的狀態
    progress.description = "%d/%d"%(page, total_pages)
    progress.value = page
    img.value = Image(filename=fn).data
Explanation: 擋掉更多廣告
End of explanation
from urllib.request import urlopen
from multiprocessing.pool import ThreadPool
%%timeit -n 1 -r 1
book_no = 63
browser.load(base_url+str(book_no))
total_pages = int(browser.runjs('ps')) 
def save_img(img_url, page):
    fn = os.path.join(dir_name, "{:03d}.jpg".format(page))
    with urlopen(img_url) as img_src:
        with open(fn, "wb") as f:
            f.write(img_src.read())
        # 更新 widget 的狀態
        progress.value += 1
        progress.description = "img: %d/%d"%(progress.value, total_pages)
        img.value = "<img src='{}' height=300 />".format(fn)
# 建立 Image Widget 用來顯示圖片預覽
img = W.HTML()
# 顯示下載進度的 Progress bar
progress = W.IntProgress(min=1, value=1, max=total_pages)
display(progress)
display(img)
dir_name = os.path.join("download", "{:02d}".format(book_no))
if not os.path.exists(dir_name):
            os.makedirs(dir_name) 
print("Download to {}".format(os.path.join(os.getcwd(), dir_name)))
sys.stdout.flush()
pool = ThreadPool(5)
for page in range(1, total_pages+1):
    # 取得 image url
    browser.load("{}{}-{}".format(base_url, book_no, page))
    img_url = browser.runjs('document.getElementById("TheImg").getAttribute("src")')
    pool.apply_async(save_img, (img_url, page))
pool.close()
pool.join()
Explanation: 利用 thread
End of explanation
<END_TASK>