事件的原由是這個樣子的,今天原本打算登陸 CSDN 看個人之前的一篇博客,結果登錄的時候是這個樣子的:html
這已經不是第一次 CSDN 這麼幹了,以前讓我驗證用手機編輯短信發送驗證已經噁心到我了。這一次簡直讓我忍無可忍。難道就是爲了強行推官一波公衆號。CSDN 的博客我從 15 年開始維護,後來其實都不是很喜歡,但畢竟是維護了一個蠻久的平臺,這一次我終於不能忍了,不再要忍受醜陋的模塊,不再要忍受噁心的廣告,不再要忍受這鬼邏輯。可是我以前的博客我得保存下來,立刻動手。python
原本想裝個逼,心想半個小時寫個爬蟲不就搞定了,人生苦短,我有 python. Naive。又折騰了好幾個小時,兜兜轉轉。廢話不說,先分析網絡請求吧。我只但願保存博客的 markdown 格式文件,我首先打開文章編輯,老規矩,打開控制檯網絡窗口,看看請求,搞很差 xhr 裏面就有,果不其然:git
哈哈,一目瞭然,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 塞進去請求,結果仍是不行。哇。後來我才發現:數組
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 或者掃描二維碼關注公衆號: