快上車,scrapy爬蟲飆車找福利(三)

swensun發表於2017-12-28

前面文章講到怎麼提取動態網頁的全部內容。接下來返回文章一,怎麼登入並且儲存登入狀態,以便帶上cookies下次訪問。

步驟

  1. 利用selenium登入知乎, 登入成功後儲存cookies 到本地。
  2. 請求之前讀取cookies, 載入cookies訪問,看是否成功登入。

詳細步驟:

  1. 利用selenium登入知乎 回到文章一, 從自從有了知乎,再也不用找福利了……連結開始。 從提取標題開始:
    image.png
if __name__ == '__main__':
   url = 'https://www.zhihu.com/collection/146079773'
   res = requests.get(url, verify=False)
   resSoup = BeautifulSoup(res.content, 'lxml')
   items = resSoup.select("div > h2 > a")
   print(len(items))
複製程式碼

verify=False:取消ssl的驗證。 執行這段程式碼, 輸出結果未0, 貼上該網頁到一個沒有登入知乎的瀏覽器開啟,重定向到登入頁, 說明需要登入。

驗證:

if __name__ == '__main__':
    url = 'https://www.zhihu.com/collection/146079773'
    # res = requests.get(url, verify=False)
    driver = webdriver.Chrome()
    driver.get(url)
    driver.implicitly_wait(2)
    res = driver.page_source
    resSoup = BeautifulSoup(res, 'lxml')
    items = resSoup.select("div > h2 > a")
    print(len(items))
複製程式碼

執行程式碼,開啟瀏覽器,顯示知乎登入頁,說明訪問收藏夾需要登入。

image.png

登入技巧: 使用selenium開啟登入頁,設定延時時間(比如60s),手動輸入賬號密碼登入知乎,60秒之後儲存cookies到本地,完成登入。後續請求攜帶儲存的cookie進行的登入。如果cookies過期,則簡單重複這一步驟。 下面是詳細步驟:


if __name__ == '__main__':

    ssl._create_default_https_context = ssl._create_unverified_context
    # url = 'https://www.zhihu.com/collection/146079773'
    url = "https://www.zhihu.com/signin"
    # res = requests.get(url, verify=False)
    driver = webdriver.Chrome()
    driver.implicitly_wait(5)
    driver.get(url)
    time.sleep(40)
    cookies = driver.get_cookies()
    pickle.dump(cookies, open("cookies.pkl", "wb"))
    print("save suc")
複製程式碼

執行這段程式碼,看是否有cookies.pkl檔案生成, 成功儲存了cookies。

接下來用第二段程式碼去驗證。

if __name__ == '__main__':
    cookies = pickle.load(open("cookies.pkl", "rb"))
    url = 'https://www.zhihu.com/collection/146079773'
    driver = webdriver.Chrome()
    driver.get("https://www.zhihu.com/signin")
    for cookie in cookies:
        print(cookie)
        driver.add_cookie(cookie)
    driver.get(url)
    driver.implicitly_wait(2)
    res = driver.page_source
    resSoup = BeautifulSoup(res, 'lxml')
    items = resSoup.select("div > h2 > a")
    print(len(items))
複製程式碼

開啟瀏覽器, 載入任意網頁,接著載入cookies, 開啟給定的url。執行程式碼,

image.png
如上,看到列印的cookies和提取的10個標題, 開啟瀏覽器,頁面不是登入頁,說明登入成功。看cookies的有效時間。即可知道下次cookies的替換時間。

至此,最難定義的動態網頁和登入問題已經解決。 下面就是怎麼儲存抓到的資料。 我的想法是先將需要登入的10頁中所有問題和問題連結提取出來,儲存為json檔案以後後續處理。接著對每一個問題下的所有圖片連結提取,儲存或者直接下載就看個人選擇了。

  1. 提取該收藏夾下的全部連結儲存到為json檔案或者txt檔案。 回到爬蟲,現在我們已經有了cookies,可以不用selenium很快的儲存問題列表。 將上一步儲存的cookies.pkl複製一份到根目錄,或者配置開啟屬性。 首先取消settings.py檔案中的中間鍵,
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    # 'zhihu.middlewares.PhantomJSMiddleware': 100,
}
複製程式碼

反爬蟲策略: 對於訪問過快,網頁一般會靜止訪問或者直接封ip。因此對於需要登入的爬蟲來說,限制訪問速度,比如5秒/次, 或者每個ip每分鐘最大訪問次數。對於不需要登入的頁面來說,使用代理ip是最好的選擇,或者降低訪問次數都是可行的辦法。 settings.py檔案的設定,

# Configure maximum concurrent requests performed by Scrapy (default: 16)
# CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 2
# The download delay setting will honor only one of:
# CONCURRENT_REQUESTS_PER_DOMAIN = 16
# CONCURRENT_REQUESTS_PER_IP = 16
複製程式碼

這幾個選項都是控制訪問速度的,一般我設定DOWNLOAD_DELAY即可,即每兩秒訪問一次。

執行程式碼如下:

class Zhihu(scrapy.Spider):
    name = "zhihu"
    cookeis = pickle.load(open("cookies.pkl", "rb"))
    urls = []
    questions_url = set()
    for i in range(1, 11):
        temp_url = "https://www.zhihu.com/collection/146079773?page=" + str(i)
        urls.append(temp_url)

    def start_requests(self):
        for url in self.urls:
            request = scrapy.Request(url=url, callback=self.parse, cookies=self.cookeis)
            yield request

    def parse(self, response):
        print(response.url)
        resSoup = BeautifulSoup(response.body, 'lxml')
        items = resSoup.select("div > h2 > a")
        print(len(items))
        for item in items:
            print(item['href'])
            self.questions_url.add(item['href'] + "\n")

    @classmethod
    # 訊號的使用
    def from_crawler(cls, crawler, *args, **kwargs):
        print("from_crawler")
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_closed)
        return s

    def spider_opened(self, spider):
        print("spider close, save urls")
        with open("urls.txt", "w") as f:
            for url in self.questions_url:
                f.write(url)
複製程式碼

命令列執行爬蟲,檢視url.txt檔案。

image.png

可以看到,成功抓取了44個連結,去除people, zhuanlan等幾個無效連結, 後面即可從該檔案讀取內容,拼接連結,利用selenium做中間鍵提取所有的圖片連結。

總結:這本文章講了如何利用selenium去手動登入網站,儲存cookies,以後後續登入(幾乎可以登入所有的網站,限制訪問速度避免被封)。

這三篇文章講解了怎麼使用scrapy去抓取想要的東西。現在無需使用框架,也可以涉及實現自己的爬蟲。對於怎麼儲存圖片,使用代理,後面會做簡單介紹。 後面會寫一篇怎麼將爬蟲部署在伺服器上,利用docker搭建python環境去執行爬蟲。

weixin:youquwen1226
github
歡迎來信探討。

相關文章