python爬取vue2官方文檔

本文原地址


目錄

文檔下載地址
可運行源程序及說明
抓取過程簡單分析


vue離線文檔下載地址


該文檔是vue2版本離線中文文檔,由爬蟲程序在官網爬取,包括文檔、api、示例、風格指南等幾個部分,下載地址是:vue2離線文檔

可運行源程序及說明


爲了程序的正常運行,需要按一下目錄建立文件夾和文件,這個層次目錄是根據源網站的目錄建立的,通過瀏覽器的開發者模式可以看到

主程序:vue_crawl.py

import requests
import re
import time
class VueCrawl:
    headers = {
        'Referer': 'https://vuejs.bootcss.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
    }
    # 網站根目錄
    base_url = 'https://vuejs.bootcss.com'
    # v2版本根索引目錄
    index_url = 'https://vuejs.bootcss.com/v2/'
    # 爬取目標
    targets = ['style-guide', 'api', 'cookbook', 'examples', 'guide']
    # 存放文檔的根目錄
    base_dir = 'D:/code/python/vue_crawl/vue_files'

    # 提取url的正則表達式
    url_pattern = re.compile(r"<a\s+[^>]*href=\"([^#>\"]*)\"[^>]*>([^<]*)</a>")
    # 提取css的正則表達式
    css_pattern = re.compile(r"<link\s+[^>]*stylesheet[^>]*\s+href=\"([^#>\"]*)\"[^>]*>")
    # 提取js的正則表達式
    js_pattern = re.compile(r"<script\s+[^>]*src=\"([^>\"]*)\"[^>]*>\s*</script>")
    # 提取img的正則表達式
    img_pattern = re.compile(r"<img\s+[^>]*src=\"([^>\"]*)\"[^>]*>")
    # 由於爬取到的靜態資源可能重複,所以用set存放
    css_set = set()
    js_set = set()
    img_set = set()
    # 抓取資源文件失敗時記錄錯誤信息
    error_info = []

    @staticmethod
    def download(abspath, content):
        """存儲資源文件,參數content爲二進制形式"""
        with open(abspath, 'wb')as f:
            f.write(content)

    def fix_pagesurl(self, content):
        """修正鏈接路徑爲相對路徑,否則爬下來的鏈接不會指向正確的位置"""
        res_text = content.decode('utf-8', errors='ignore')
        css_search_res = self.css_pattern.findall(res_text)
        # css鏈接到base_dir目錄的css文件夾下
        for item in css_search_res:
            if not item.startswith(('http://', 'https://')):
                self.css_set.add(item)
                res_text = res_text.replace(item, "../.." + item)

        js_search_res = self.js_pattern.findall(res_text)
        # js鏈接到base_dir目錄的js文件夾下
        for item in js_search_res:
            if not item.startswith(('http://', 'https://')):
                self.js_set.add(item)
                res_text = res_text.replace(item, "../.." + item)

        img_search_res = self.img_pattern.findall(res_text)
        # 圖片鏈接到base_dir目錄的images文件夾下
        for item in img_search_res:
            if not item.startswith(('http://', 'https://')):
                self.img_set.add(item)
                res_text = res_text.replace(item, "../.." + item)

        url_search_res = self.url_pattern.findall(res_text)
        # 文檔鏈接到當前文件夾下
        for item in url_search_res:
            item_url = item[0]
            if not item_url.startswith(('http://', 'https://')) and (
                    item_url.startswith("/v2/") and item_url.endswith('.html')):
                res_text = res_text.replace(item_url, "./" + item_url.split('/')[-1])
        return res_text.encode('utf-8')

    def crawl_pages(self, target):
        """根據target [style-guide','api','cookbook','examples','guide']這幾個主要部分爬取"""
        url_set = set()
        init_r = requests.get(self.index_url + target, headers=self.headers)
        init_text = init_r.content.decode('utf-8', errors='ignore')

        url_search_res = self.url_pattern.findall(init_text)
        for item in url_search_res:
            item_url = item[0]
            if not item_url.startswith(('http://', 'https://')) and (
                    item_url.startswith("/v2/" + target) and item_url.endswith('.html')):
                url_set.add(item_url)

        # 下載每個部分的首頁
        VueCrawl.download(self.base_dir + '/v2/' + target + '/index.html', content=self.fix_pagesurl(init_r.content))

        # 對首頁部分所有判定有效的鏈接進行下載
        for item in url_set:
            try:
                filename = item.split('/')[-1]
                res = requests.get(self.base_url + item, headers=self.headers)
                print(str(res.status_code) + ":" + res.url)
                res_content = res.content
                VueCrawl.download(self.base_dir + '/v2/' + target + '/' + filename,
                                  content=self.fix_pagesurl(res_content))
                print('download file %s' % filename)
                time.sleep(2)
            except:
                info = 'download file %s faild' % item
                print(info)
                self.error_info.append(info)

    def download_staticfiles(self):
        """下載靜態資源文件"""
        for item in self.js_set | self.img_set | self.css_set:
            try:
                res_content = requests.get(self.base_url + item, headers=self.headers).content
                self.download(self.base_dir + item, res_content)
                time.sleep(1)
            except:
                info = 'download file %s faild' % item
                print(info)
                self.error_info.append(info)

    def main(self):
        """主體部分 首先爬文檔,之後下載靜態資源文件"""
        for target in self.targets:
            self.crawl_pages(target)

        self.download_staticfiles()


if __name__ == '__main__':
    init_r = VueCrawl().main()

抓取過程分析


主要抓取的東西有幾個大頁面,在程序中根據url寫死就行了,如下圖:

# 要抓取的幾個大部分
targets = ['style-guide', 'api', 'cookbook', 'examples', 'guide']

每個大部分左側又有許多單獨頁面,需要一一抓取,如下圖:

主要鏈接需要用正則表達式提取出來,不提取包含#的鏈接,不然會造成重複抓取,不抓取其他域名下的鏈接,這裏判斷的比較簡單,直接判斷是否以http,https開頭:

# url_pattern = re.compile(r"<a\s+[^>]*href=\"([^#>\"]*)\"[^>]*>([^<]*)</a>")

url_set = set()
init_r = requests.get(self.index_url + target, headers=self.headers)
init_text = init_r.content.decode('utf-8', errors='ignore')

url_search_res = self.url_pattern.findall(init_text)
for item in url_search_res:
	item_url = item[0]
	if not item_url.startswith(('http://', 'https://')) and (item_url.startswith("/v2/" + target) and item_url.endswith('.html')):
		url_set.add(item_url)

之後是對目標進行下載,這裏不再詳細說明,需要注意的是,在下載之前先要根據目錄改變各種資源的路徑層次結構

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章