前言
筆者之前的寫作習慣一直是在本地(Mac Ipac)寫好之后將代碼粘貼到csdn,圖片是Ipac自動上傳到微博匿名圖床上,用了大概一年多都沒有問題,直到前段時間突然發現我csdn文章里面的圖片無法加載了,就像下面這樣:
本來以為是微博圖床掛了,結果發現圖片的鏈接還是可以正常訪問的,本地上也是可以正常顯示圖片的,問了一下csdn的工作人員,說是微博圖床加了防盜鏈,所以現在csdn不能自動加載了,真是又氣又無奈,沒辦法,誰讓自己當初貪圖小便宜用了免費圖床了,既然問題已經出了就要想辦法解決,首先是訂閱了Ipac,這樣可以支持自定義圖床(默認的Ipac只能支持微博匿名圖床),筆者選擇的是阿里云Oss,有免費額度,個人圖床夠用。但是這樣只能保證我之后寫的文章不會因為圖床的導致圖片掛掉,那之前的怎么辦….如果可以將之前文章里面的圖片從圖床上下載下來,然后傳到我新的圖床上,然后再將原文的圖片鏈接由原來的圖床鏈接替換為現在新的圖片鏈接就可以完美解決了啊,但是由于文章太多,一篇一篇手動操作實在是太慢,既然是程序員,就應該用代碼解決,所以有了本文,本文的主要思路如下圖所示:
模擬登陸csdn
我們首先打開csdn的登陸頁面,這里我們選擇賬號密碼登陸,方便提取信息:
我們隨便個賬號和密碼,看看點擊登陸之后該站點會做什么:
我們發現,這里執行了一個,見名知意,這個應該就是真正的登陸的請求,我們點開看看詳情:
重點在于我用紅圈圈出來的那里,將我們輸入的用戶名和密碼傳進去您不能使用他人的圖片鏈接地址,請盡快替換,然后發起登陸請求,所以,我們只需要模擬這個就可以了,代碼如下:
def doLogin(userId, password):
"""
模擬登陸,獲取cookie以及username
:param userId:

:param password:
:return:
"""
url = "https://passport.csdn.net/v1/register/pc/login/doLogin"
payload = "{\"loginType\":\"1\",\"pwdOrVerifyCode\":\"" password "\",\"userIdentification\":\"" userId "\",..."
headers = {
'accept': "application/json, text/plain, */*",
'accept-encoding': "gzip, deflate, br",
'accept-language': "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
'content-type': "application/json;charset=UTF-8",
'origin': "https://passport.csdn.net",
'referer': "https://passport.csdn.net/login",
'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36",

'x-requested-with': "XMLHttpRequest",
'Cache-Control': "no-cache",
'Postman-Token': "407dbd4f-90ba-494c-994f-2de739d73a96,b506b3e0-b247-40af-b52b-2622c2148687",
'Host': "passport.csdn.net",
'Connection': "keep-alive",
'cache-control': "no-cache"
}
session = requests.session()
response = session.request("POST", url, data=payload.encode('utf-8'), headers=headers)
jsonObject = json.loads(bytes.decode(response.content))
if jsonObject['message'] == 'success':
print('登錄:{userId}成功'.format(userId=userId))
return session, jsonObject
else:

print('登錄:{userId}失敗:'.format(userId=userId) jsonObject['message'])
return None
這樣就完成了模擬登陸,注意這里返回的是一個和 ,是中的概念,返回就一個目的,利用登陸成功后的,這樣才能在后面修改你的文章, 是登陸成功后csdn服務端給我們返回的信息,這里將其返回的目的是獲取當前對應的(指的是你在csdn利用賬號密碼登錄時輸入的那個用戶名,一般是郵箱或者手機號碼,是csdn給你分配的一個標識)。
爬取個人所有文章的id
這里爬取所有文章id相當于獲取了當前作者的所有文章列表,我們先看看指定作者的文章列表頁:
可以看到url是:,就是剛才我們登錄時返回的那個,index是頁面的序號,因為大家基本都是很多頁文章,所以index從0往上增加,我們看看這個頁面的html代碼:
可以很容易地發現文章列表的位置,分析了一下發現每一篇文章都有一個data-,這就是我們需要的文章id啊,所以思路就是模擬請求,拿到返回的html后使用正則表達式匹配data-即可,注意這里有個細節就是您不能使用他人的圖片鏈接地址,請盡快替換,在我畫紅括弧的緊鄰上一個< div >標簽,有一個style=":none;"的元素,這個不是我們需要的,但是他也有data-屬性,所以我們在使用正則表達式匹配到當前html頁面的所有data-屬性后應該忽略第一條,代碼如下:
def getArticleIdList(userId, maxListPage=100):
"""
獲取指定userId用戶的所有文章的iD
:param userId:
:param maxListPage:

:return:
"""
articleList = []
count = 0
for index in range(maxListPage):
url = 'https://blog.csdn.net/' userId '/article/list/' str(index)
requestParm = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) ...", "Accept-Language": "en-US,en;q=0.5"}
response = requests.get(url, params=requestParm)
if response.status_code == 200:
pattern = re.compile(r"data-articleid=\".*?\"")
resultList = pattern.finditer(bytes.decode(response.content))
flag = 0
for result in resultList:
if flag == 0:
flag = flag 1

continue
print('正在獲取第{count}條文章Id'.format(count=count))
flag = flag 1
count = count 1
item = re.search("\".*?\"", result.group())
articleList.append(item.group().strip('\"'))
if flag == 0:
break
else:
break
print('共獲取到{count}條文章id'.format(count=len(articleList)))
return articleList
爬取文章
獲取到文章的id列表之后我們就可以爬取文章了,我們爬取文章的目的是獲取到當前文章的或者是html源代碼,然后在本地做圖片鏈接的替換,那么我們肯定要去文章的編輯頁面找規律,而不是在文章的詳情頁面,因為詳情頁面大概率只會返回html,不會返回源代碼,我們隨便找一篇文章,點擊"編輯",進入編輯頁面: