python爬蟲框架(2)--PySpider框架安裝配置

1.安裝

 1.phantomjs

PhantomJS 是一個基於 WebKit 的服務器端 JavaScript API。它全面支持web而不需瀏覽器支持,其快速、原生支持各類Web標準:DOM 處理、CSS 選擇器、JSON、Canvas 和 SVG。 PhantomJS 能夠用於頁面自動化、網絡監測、網頁截屏以及無界面測試等。css

http://phantomjs.org/download.htmlhtml

2.pyspider

直接利用 pip 安裝便可python

pip install pyspider

測試web

若是安裝過程沒有提示任何錯誤,那就證實一些OK。json

命令行輸入數組

pyspider all

而後瀏覽器訪問 http://localhost:5000瀏覽器

觀察一下效果,若是能夠正常出現 PySpider 的頁面,那證實一切OK服務器

3.配置環境變量

將PhantomJS放到C:\Python27\Scripts中,並將可執行程序文件所在位置以及C:\Python27\Scripts添加到環境變量的Path中網絡

2.PySpider的用法

官方文檔:http://docs.pyspider.org/en/latest/python爬蟲

1)首先在scripts文件夾下打開cmd,輸入:

pyspider all

這句命令的意思是,運行 pyspider 並 啓動它的全部組件,包括PhantomJS

2)接下來在瀏覽器中輸入 http://localhost:5000,能夠看到 PySpider 的主界面,點擊右下角的 Create,命名爲 taobaomm,固然名稱你以隨意取,繼續點擊 Create。

整個頁面分爲兩欄,左邊是爬取頁面預覽區域,右邊是代碼編寫區域。下面對區塊進行說明:

左側綠色區域:這個請求對應的 JSON 變量,在 PySpider 中,其實每一個請求都有與之對應的 JSON 變量,包括回調函數,方法名,請求連接,請求數據等等。

綠色區域右上角Run:點擊右上角的 run 按鈕,就會執行這個請求,能夠在左邊的白色區域出現請求的結果。

左側 enable css selector helper: 抓取頁面以後,點擊此按鈕,能夠方便地獲取頁面中某個元素的 CSS 選擇器。

左側 web: 即抓取的頁面的實時預覽圖。

左側 html: 抓取頁面的 HTML 代碼。

左側 follows: 若是當前抓取方法中又新建了爬取請求,那麼接下來的請求就會出如今 follows 裏。

左側 messages: 爬取過程當中輸出的一些信息。

右側代碼區域: 你能夠在右側區域書寫代碼,並點擊右上角的 Save 按鈕保存。

右側 WebDAV Mode: 打開調試模式,左側最大化,便於觀察調試。

3)開始爬取

https://mm.taobao.com/json/request_top_list.htm?page=1,其中 page 參數表明頁碼。因此咱們暫時抓取前 30 頁。頁碼到最後能夠隨意調整。

首先定義基地址,而後定義爬取的頁碼和總頁碼。

from pyspider.libs.base_handler import *


class Handler(BaseHandler): crawl_config = { } def __init__(self): self.baseurl = 'https://mm.taobao.com/json/request_top_list.htm?page=' self.page_num = 1 self.total_num = 30 @every(minutes=24 * 60) def on_start(self): while self.page_num <= self.total_num: url = self.baseurl + str(self.page_num) print url self.crawl(url, callback=self.index_page, validate_cert=False) self.page_num += 1 @config(age=10 * 24 * 60 * 60) def index_page(self, response): for each in response.doc('a[href^="http"]').items(): self.crawl(each.attr.href, callback=self.detail_page, validate_cert=False) @config(priority=2) def detail_page(self, response): return { "url": response.url, "title": response.doc('title').text(), }

點擊 save 保存代碼,而後點擊左邊的 run,運行代碼。

運行後會發現 follows 出現了 30 這個數字,說明咱們接下來有 30 個新請求,點擊可查看全部爬取列表。另外控制檯也有輸出,將全部要爬取的 URL 打印了出來。

而後點擊左側任意一個綠色箭頭,能夠繼續爬取這個頁面。例如點擊第一個 URL,來爬取這個 URL

 

4)HTTP 599: SSL certificate problem錯誤的解決方法

在 crawl 方法中加入忽略證書驗證的參數,validate_cert=False

5)修改 index_page 方法

def index_page(self, response): for each in response.doc('a[href^="http"]').items(): self.crawl(each.attr.href, callback=self.detail_page, validate_cert=False)

其中 response 就是剛纔爬取的列表頁,response 其實就至關於列表頁的 html 代碼,利用 doc 函數,實際上是調用了 PyQuery,用 CSS 選擇器獲得每個MM的連接,而後從新發起新的請求。

 好比,這裏拿到的 each.attr.href 多是 mm.taobao.com/self/model_card.htm?user_id=687471686,在這裏繼續調用了 crawl 方法,表明繼續抓取這個連接的詳情。

而後回調函數就是 detail_page,爬取的結果會做爲 response 變量傳過去。detail_page 接到這個變量繼續下面的分析。

右邊的頁面使用 JS 渲染生成的,而普通的抓取是不能獲得 JS 渲染後的頁面的,PySpider 提供了動態解析 JS 的機制。由於在前面裝好了 PhantomJS,因此,這時候就輪到它來出場了。在最開始運行 PySpider 的時候,使用了pyspider all命令,這個命令是把 PySpider 全部的組件啓動起來,其中也包括 PhantomJS。

只是簡單地加了一個 fetch_type='js',點擊綠色的返回箭頭,從新運行一下。

6)數據分析

繼續修改 detail_page 方法,而後增長一個 domain_page 方法,用來處理每一個 MM 的個性域名。

先點擊F12打開開發者選項,找到mm的個性域名模塊

.mm-p-domain-info li > span指的是從域名地點的div標籤到span標籤的路徑上的全部祖先節點。再加上」https:」就構成了個性域名的URL。以後利用self.crawl來繼續對domain這個頁面進行爬取。(CSS選擇器詳見python爬蟲(7)--Beautiful Soup的用法

def detail_page(self, response): domain = 'https:' + response.doc('.mm-p-domain-info li > span').text() print domain self.crawl(domain, callback=self.domain_page) def domain_page(self,response): pass

繼續從新 run,預覽一下頁面,看到了 MM 的全部圖片。

7)保存

完善 domain_page 代碼,實現保存簡介和遍歷保存圖片的方法。

在這裏,PySpider 有一個特色,全部的 request 都會保存到一個隊列中,並具備去重和自動重試機制。因此,最好的解決方法是,把每張圖片的請求都寫成一個 request,而後成功後用文件寫入便可,這樣會避免圖片加載不全的問題。

import os class Deal: def __init__(self): self.path = DIR_PATH if not self.path.endswith('/'): self.path = self.path + '/'
        if not os.path.exists(self.path): os.makedirs(self.path) def mkDir(self, path): path = path.strip() dir_path = self.path + path exists = os.path.exists(dir_path) if not exists: os.makedirs(dir_path) return dir_path else: return dir_path def saveImg(self, content, path): f = open(path, 'wb') f.write(content) f.close def saveBrief(self, content, dir_path, name): file_name = dir_path + "/" + name + ".txt" f = open(file_name, "w+") f.write(content.encode('utf-8')) def getExtension(self, url): extension = url.split('.')[-1] return extension

這裏麪包含了四個方法。

mkDir:建立文件夾,用來建立 MM 名字對應的文件夾。

saveBrief: 保存簡介,保存 MM 的文字簡介。

saveImg: 傳入圖片二進制流以及保存路徑,存儲圖片。

getExtension: 得到連接的後綴名,經過圖片 URL 得到。

而後在 domain_page 中具體實現以下

def domain_page(self,response): name = response.doc('.mm-p-model-info-left-top dd > a').text() dir_path = self.deal.mkDir(name) brief = response.doc('.mm-aixiu-content').text() if dir_path: imgs = response.doc('.mm-aixiu-content img').items() count = 1 self.deal.saveBrief(brief, dir_path, name) for img in imgs: url = img.attr.src if url: extension = self.deal.getExtension(url) file_name = name + str(count) + '.' + extension count += 1 self.crawl(img.attr.src, callback=self.save_img, save={'dir_path':dir_path, 'file_name':file_name}, validate_cert=False) def save_img(self, response): content = response.content dir_path = response.save['dir_path'] file_name = response.save['file_name'] file_path = dir_path + '/' + file_name self.deal.saveImg(content, file_path)

以上方法首先獲取了頁面的全部文字,而後調用了 saveBrief 方法存儲簡介。

而後遍歷了 MM 全部的圖片,並經過連接獲取後綴名,和 MM 的姓名以及自增計數組合成一個新的文件名,調用 saveImg 方法保存圖片。

完善代碼以下:

#!/usr/bin/env python # -*- encoding: utf-8 -*- # Created on 2018-01-24 17:33:28 # Project: taobaomm

from pyspider.libs.base_handler import * DIR_PATH = '/var/py/mm'

class Handler(BaseHandler): crawl_config = { } def __init__(self): self.baseurl = 'https://mm.taobao.com/json/request_top_list.htm?page=' self.page_num = 1 self.total_num = 30 self.deal = Deal() @every(minutes=24 * 60) def on_start(self): while self.page_num <= self.total_num: url = self.baseurl + str(self.page_num) print url self.crawl(url, callback=self.index_page, validate_cert=False) self.page_num += 1 @config(age=10 * 24 * 60 * 60) def index_page(self, response): for each in response.doc('a[href^="http"]').items(): self.crawl(each.attr.href, callback=self.detail_page, fetch_type='js', validate_cert=False) @config(priority=2) def detail_page(self, response): domain = 'https:' + response.doc('.mm-p-domain-info li > span').text() print domain self.crawl(domain, callback=self.domain_page, validate_cert=False) def domain_page(self,response): name = response.doc('.mm-p-model-info-left-top dd > a').text() dir_path = self.deal.mkDir(name) brief = response.doc('.mm-aixiu-content').text() if dir_path: imgs = response.doc('.mm-aixiu-content img').items() count = 1 self.deal.saveBrief(brief, dir_path, name) for img in imgs: url = img.attr.src if url: extension = self.deal.getExtension(url) file_name = name + str(count) + '.' + extension count += 1 self.crawl(img.attr.src, callback=self.save_img, save={'dir_path':dir_path, 'file_name':file_name}, validate_cert=False) def save_img(self, response): content = response.content dir_path = response.save['dir_path'] file_name = response.save['file_name'] file_path = dir_path + '/' + file_name self.deal.saveImg(content, file_path) import os class Deal: def __init__(self): self.path = DIR_PATH if not self.path.endswith('/'): self.path = self.path + '/'
        if not os.path.exists(self.path): os.makedirs(self.path) def mkDir(self, path): path = path.strip() dir_path = self.path + path exists = os.path.exists(dir_path) if not exists: os.makedirs(dir_path) return dir_path else: return dir_path def saveImg(self, content, path): f = open(path, 'wb') f.write(content) f.close def saveBrief(self, content, dir_path, name): file_name = dir_path + "/" + name + ".txt" f = open(file_name, "w+") f.write(content.encode('utf-8')) def getExtension(self, url): extension = url.split('.')[-1] return extension
相關文章
相關標籤/搜索