Bye, CSDN

原由

事件的原由是這個樣子的,今天原本打算登陸 CSDN 看個人之前的一篇博客,結果登錄的時候是這個樣子的:html

blackman.jpg

這已經不是第一次 CSDN 這麼幹了,以前讓我驗證用手機編輯短信發送驗證已經噁心到我了。這一次簡直讓我忍無可忍。難道就是爲了強行推官一波公衆號。CSDN 的博客我從 15 年開始維護,後來其實都不是很喜歡,但畢竟是維護了一個蠻久的平臺,這一次我終於不能忍了,不再要忍受醜陋的模塊,不再要忍受噁心的廣告,不再要忍受這鬼邏輯。可是我以前的博客我得保存下來,立刻動手。python

動手

原本想裝個逼,心想半個小時寫個爬蟲不就搞定了,人生苦短,我有 python. Naive。又折騰了好幾個小時,兜兜轉轉。廢話不說,先分析網絡請求吧。我只但願保存博客的 markdown 格式文件,我首先打開文章編輯,老規矩,打開控制檯網絡窗口,看看請求,搞很差 xhr 裏面就有,果不其然:git

csdn-markdown.png

哈哈,一目瞭然,markdowncontent 不正是咱們須要的麼。內心頓時以爲半個小時更穩了。爬蟲,固然是 requests,據說這個庫的做者最近又出了 requests-html 正好能夠用來解析。前面都很順利,分析頁面,看看博客內容一共有多少頁,而後在每一頁獲取博客的 articleid 再去請求博客。github

def get_page_urls(html):
    page_urls_arr = []
    page_urls = html.find('.pagination-wrapper .page-item a')
    for page_url in page_urls:
        if 'href' in page_url.attrs:
            href = page_url.attrs['href']
            page_urls_arr.append(href)
            print(href)
        page_urls_arr = list(set(page_urls_arr))
    return page_urls_arr
    
 def get_article_id_list(url):
    id_list = []
    r = session.get(url)
    html = r.html
    page_urls = get_page_urls(html)
    for page_url in page_urls:
        id_list = id_list + get_article_ids_by_page(page_url)
    # print(id_list)
    return id_list


def get_article_ids_by_page(page_url):
    r = session.get(page_url)
    html = r.html
    article_ids = html.find('.blog-unit a')
    article_isd_arr = []
    for article_id in article_ids:
        href = article_id.attrs['href']
        article_isd_arr.append(parse_article_id(href))
    return article_isd_arr


def parse_article_id(url):
    return url.replace('http://blog.csdn.net/neal1991/article/details/', '')
複製代碼

咱們這樣就能夠獲取一個 article_id 組成的數組,而後經過和 ttp://mp.blog.csdn.net/mdeditor/getArticle?id= 拼接組成 url 就能夠去請求博客了。chrome

問題

很顯然,我低估了問題嗎,或許也能夠說我沒有從一個正確的角度去思考這個問題。去訪問這個文章是須要權限的,也就是須要登錄以後才能夠訪問,我嘗試直接訪問,響應都是無權操做。那咱們就登錄好了:json

session = HTMLSession()
r = session.post(login_url, auth=(username, passwd))
session.get(url)
複製代碼

這裏其實就是這個大概的意思,經過 session 彷佛是能夠直接訪問的,可是仍是不能夠。後來我嘗試首先獲取 cookies,而後再次請求的時候把 cookies 塞進去請求,結果仍是不行。哇。後來我才發現:數組

login.png

CSDN 果真不是通常的噁心,每次登錄的時候會給一個流水號,登錄驗證的時候須要驗證這個流水號,可是你拿 cookies 的時候和登錄的時候流水號不一致,因此沒法經過驗證。後來想到或許可使用 headless chrome,因而就去用 puppeteer,使用體驗和phantomjs 相似,順嘴提一句,phantomjs 感受都快不行了,最近維護者又內訌了。這種方式仍是比較低效,並且還得去慢慢調試,最後仍是用 python 吧。瀏覽器

找到了我最不肯意使用的方法,先從瀏覽器中把 cookies 拷貝下來,而後再去請求。由於一開始內心老是接受不了這種半自動化的方式,顯得太 low。白貓黑貓,抓到老鼠就能夠了。罷了。微信

def parse_cookie(str):
    cookies = {}
    for line in str.split(';'):
        name, value = line.strip().split('=', 1)
        cookies[name] = value
    return cookies
複製代碼
def get_markdown_files(id_list, base_url):
   for id in id_list:
       url = base_url + id
       get_markdown(url)

def get_markdown(url):
   cookies = parse_cookie(config['cookies'])
   r = requests.get(url, cookies=cookies)
   data = r.json()['data']
   title = data['title']
   markdown_content = data['markdowncontent']
   invalid_characaters = '\\/:*?"<>|'
   for c in invalid_characaters:
       title = title.replace(c, '')
   generate_file('data/' + title.strip() + '.md', markdown_content)


def generate_file(filename, content):
   if not os.path.exists(filename):
       if content is None:
           print(filename + 'is none')
       else:
           print(filename)
           with open(filename, 'w', encoding='utf8') as f:
               f.write(content)
               f.close()
複製代碼

這裏有幾點注意一下,首先須要 format 下 cookies,而後就是文件名中的特殊字符須要轉義,不然 oepn 會提示 FileNotFound。markdown

結語

無論怎麼樣,最終問題仍是解決了,雖然不是一開始指望的方式。其實有時候常常以爲寫代碼好費勁,沒有一次是刷刷刷就把代碼所有寫出來,還要不斷地調試,不斷地 解決問題,最終才能達到目的。最終發花了幾個小時,寫了這幾小段代碼,一個小時寫了這篇文章總結。累。

以上。

歡迎搜索微信號 mad_coder 或者掃描二維碼關注公衆號:

9tMvlT.jpg
相關文章
相關標籤/搜索