写点什么

根据码龄来爬取 CSDN 博客粉丝

用户头像
空城机
关注
发布于: 2021 年 04 月 01 日
根据码龄来爬取CSDN博客粉丝

又是一周周末了,闲暇无事,很有精神, 准备看一下 csdn 社区中码龄 20 年以上的大佬们人数有多少!


该如何查看呢,当然是使用爬虫了。构思是爬取一位用户博客中的粉丝,然后依靠这些粉丝的粉丝,把社区中的用户都爬取一遍,筛选出码龄二十年以上的大佬。单点开花,从一到多。


但是人类是有极限的,想法很好(可能存在从没关注过别人并且没有粉丝的用户),实施好麻烦,声音那么小还想写爬虫。

所以从入门到放弃,只完成了爬取单用户的博客粉丝给自己交工,哈哈哈<( ̄▽ ̄)/

在此确定一下需求:爬取某位用户的粉丝基础数据,根据粉丝的码龄来筛选出码龄 20 年以上的用户。一般 csdn 的博主很少会有 20 年以上的粉丝,所以爬取的目标就确定为 csdn 官方博客账号下的粉丝


正文开始

IP 代理

根据以前爬虫被封的经验,还是得准备一份 IP 来打个保险。这个保险还是有必要的,之前我学习 python 爬虫曾经年轻过,结果被封过 IP 地址,第二天幸好解封了。

可参考:https://blog.csdn.net/qq_36171287/article/details/113095615


#  获取IP代理def get_ip_list(headers, page):    ip_list = []    for i in range(int(page)):        # 爬取免费的IP        url = 'https://www.kuaidaili.com/free/inha/{}/'.format(i+1)        # print("爬取网址为:", url)        #获取代理IP地址        web_data = requests.get(url, headers=headers)        if web_data.status_code == 200:            tree0 = etree.HTML(web_data.text)            ip_lists = tree0.xpath('//table/tbody/tr/td[@data-title="IP"]/text()');            port_lists = tree0.xpath('//table/tbody/tr/td[@data-title="PORT"]/text()')            type_lists = tree0.xpath('//table/tbody/tr/td[@data-title="类型"]/text()')            # print(ip_lists)            # print(port_lists)            for x,y in zip(ip_lists, port_lists):                ip_list.append(x + ":" + y)            time.sleep(3)  # 防止访问频率过快,被封    # print(len(ip_list))    return ip_list
复制代码


不过每次从网上查找 IP 太麻烦了,干脆把爬取到的 IP 地址记录下来,放在 txt 中,下次直接从 txt 当中把 IP 拿出来,返回一个随机 IP。大家也可以先存储到数据库当中,然后从数据库当中获取出来,不过现在太麻烦了,所以可以直接放入 txt。

记录 IP 到 txt 中


#  记录IP到txtdef save_ip_list():    header = {'User-Agent': random.choice(user_agent_list)}    ip_list = get_ip_list(headers=header, page=3)    with open('userCsdn/ipList.txt', 'a') as fp:        for ip in ip_list:            fp.write('http:' + ip + '\n')        print('记录完成')        fp.close()
复制代码


获取 IP (注意:从 txt 中获取回来 IP 时会返回\n,所以要 strip 截取掉\n)


# 读取IP——txt,返回一个随机IPdef return_ip():    with open('userCsdn/ipList.txt', 'r') as fp:        ip_list = fp.readlines()        fp.close()    ip = random.choice(ip_list)    ip = ip.strip('\n')    return ip
复制代码



请求头

准备好一些请求头,之后访问时随机使用


user_agent_list=[    'Mozilla/5.0(compatible;MSIE9.0;WindowsNT6.1;Trident/5.0)',    'Mozilla/4.0(compatible;MSIE8.0;WindowsNT6.0;Trident/4.0)',    'Mozilla/4.0(compatible;MSIE7.0;WindowsNT6.0)',    'Opera/9.80(WindowsNT6.1;U;en)Presto/2.8.131Version/11.11',    'Mozilla/5.0(WindowsNT6.1;rv:2.0.1)Gecko/20100101Firefox/4.0.1',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',    'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)',    'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60',    'Opera/8.0 (Windows NT 5.1; U; en)',    'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50',    'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50',    'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',    'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11']
复制代码


使用方式


header = {'User-Agent': random.choice(user_agent_list)}
复制代码



cookie

可以从网上找一个 cookie 来伪装一下,虽然未必有用ㄟ( ▔, ▔ )ㄏ


cookies = dict(uuid='b18f0e70-8705-470d-bc4b-09a8da617e15', UM_distinctid='15d188be71d50-013c49b12ec14a-3f73035d-100200-15d188be71ffd')
复制代码



接口分析

准备爬取某个用户的粉丝数量信息,那就要先找到对应的入口。csdn 官方博客的页面如下(其实相比我爬取时已经变成新的博客页面了,不过接口应该还没有失效): https://blog.csdn.net/blogdevteam


直接访问页面,获取到的结果中可是没有粉丝信息的page_text = requests.get('https://blog.csdn.net/blogdevteam', headers=header, cookies=cookies, proxies=proxies)


这样就说明了,粉丝信息是动态加载出来的,打开控制台,从 Network 中进行分析



由上面的步骤,get 到了粉丝信息的接口:https://blog.csdn.net//phoenix/web/v1/fans/list?page=1&pageSize=40&blogUsername=blogdevteam


嗯,分析一下接口传参(这里没法弄表格啊!):


返回的数据


接口数据分析



爬虫数据保存

先提前准备两个方法


根据码龄创建 txt 文件


# 根据码龄创建txt文件def mdtxt(year):    if not os.path.exists('./userCsdn/userCsdn_' + str(year) + '.txt'):        file = open('./userCsdn/userCsdn_' + str(year) + '.txt', 'w')        file.close()
复制代码


根据码龄保存数据到 txt 中


# 将数据保存至txt中def saveTxt(year, data):    with open('userCsdn/userCsdn_' + str(year) + '.txt', 'a', encoding="utf-8") as fp:        fp.write(str(data) + '\n')        fp.close()
复制代码



重点,爬取数据方法

编写一个爬取上面接口分析的粉丝接口的方法函数方法的参数:博客主人的 id、需要爬取第几页、一个随机 ip


在方法中,response = requests.get(fans_url, param, headers=header, cookies=cookies, proxies=proxies)


response 返回的结果是 json,所以使用.json()方法转换


在 json 数据中分析,如果 years 大于等于 20,就根据具体码龄,判断是否有此年龄的 txt 文件,没有就创建,并且将数据记录到相对应的 txt 当中


fansNums = 0; # 找到的粉丝数# 主要方法,寻找符合条件的粉丝def findFans( userid, page, ip ):    global fansNums    fans_url = 'https://blog.csdn.net//phoenix/web/v1/fans/list'    param = {         'page': page,        'pageSize': '50',        'blogUsername': userid    }    cookies = dict(uuid='b18f0e70-8705-470d-bc4b-09a8da617e15', UM_distinctid='15d188be71d50-013c49b12ec14a-3f73035d-100200-15d188be71ffd')    header = {'User-Agent': random.choice(user_agent_list)}    proxies = {'http': ip}    response = requests.get(fans_url, param, headers=header, cookies=cookies, proxies=proxies)    page_json = response.json()    for item in page_json['data']['list']:        if (int(item['years']) >= 20):            mdtxt(int(item['years']))            saveTxt(int(item['years']), item)            fansNums = fansNums + 1
复制代码



多线程爬取

因为要爬取的官方博客的粉丝数量有 3 万多个,分页的话,最多每页 50 个,相当于 35251/50 = 705。所以这里建议开多线程进行数据爬取,可参考:python爬虫系列——开始入土(四)


多线程调用方法进行爬取


def forSave(range_list):    for page in range(range_list[0], range_list[1]):        findFans('blogdevteam', str(page), ip)        print('page', page,'记录完成 码龄20年以上粉丝数:', fansNums)
if __name__ == '__main__': ip = return_ip() header = {'User-Agent': random.choice(user_agent_list)} range_lists = [[1, 141], [142, 283], [284, 424], [425, 564], [565, 706]] pool = Pool(5) pool.map(forSave, range_lists) pool.close() pool.join()
复制代码



完整代码

import requestsimport timeimport randomfrom lxml import etreeimport osfrom multiprocessing.dummy import Pool
user_agent_list=[ 'Mozilla/5.0(compatible;MSIE9.0;WindowsNT6.1;Trident/5.0)', 'Mozilla/4.0(compatible;MSIE8.0;WindowsNT6.0;Trident/4.0)', 'Mozilla/4.0(compatible;MSIE7.0;WindowsNT6.0)', 'Opera/9.80(WindowsNT6.1;U;en)Presto/2.8.131Version/11.11', 'Mozilla/5.0(WindowsNT6.1;rv:2.0.1)Gecko/20100101Firefox/4.0.1', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)', 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60', 'Opera/8.0 (Windows NT 5.1; U; en)', 'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0', 'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11']
# 获取IP代理def get_ip_list(headers, page): ip_list = [] for i in range(int(page)): # 爬取免费的IP url = 'https://www.kuaidaili.com/free/inha/{}/'.format(i+1) # print("爬取网址为:", url) #获取代理IP地址 web_data = requests.get(url, headers=headers) if web_data.status_code == 200: tree0 = etree.HTML(web_data.text) ip_lists = tree0.xpath('//table/tbody/tr/td[@data-title="IP"]/text()'); port_lists = tree0.xpath('//table/tbody/tr/td[@data-title="PORT"]/text()') type_lists = tree0.xpath('//table/tbody/tr/td[@data-title="类型"]/text()') # print(port_lists) for x,y in zip(ip_lists, port_lists): ip_list.append(x + ":" + y) time.sleep(3) # 防止访问频率过快,被封 return ip_list
# 记录IP到txtdef save_ip_list(): header = {'User-Agent': random.choice(user_agent_list)} ip_list = get_ip_list(headers=header, page=3) with open('userCsdn/ipList.txt', 'a') as fp: for ip in ip_list: fp.write('http:' + ip + '\n') print('记录完成') fp.close()
# 读取IP——txt,返回一个随机IPdef return_ip(): with open('userCsdn/ipList.txt', 'r') as fp: ip_list = fp.readlines() fp.close() ip = random.choice(ip_list) ip = ip.strip('\n') return ip
############################################################### 用户主页,实际上没有用到def findCsdnPage( url, ip ): # 伪造cookie cookies = dict(uuid='b18f0e70-8705-470d-bc4b-09a8da617e15', UM_distinctid='15d188be71d50-013c49b12ec14a-3f73035d-100200-15d188be71ffd') header = {'User-Agent': random.choice(user_agent_list)} proxies = {'http': ip} page_text = requests.get(url, headers=header, cookies=cookies, proxies=proxies) print(page_text.text)
# 将数据保存至txt中def saveTxt(year, data): with open('userCsdn/userCsdn_' + str(year) + '.txt', 'a', encoding="utf-8") as fp: fp.write(str(data) + '\n') fp.close()# 根据码龄创建txt文件def mdtxt(year): if not os.path.exists('./userCsdn/userCsdn_' + str(year) + '.txt'): file = open('./userCsdn/userCsdn_' + str(year) + '.txt', 'w') file.close()
fansNums = 0; # 找到的粉丝数# 主要方法,寻找符合条件的粉丝def findFans( userid, page, ip ): global fansNums fans_url = 'https://blog.csdn.net//phoenix/web/v1/fans/list' param = { 'page': page, 'pageSize': '50', 'blogUsername': userid } cookies = dict(uuid='b18f0e70-8705-470d-bc4b-09a8da617e15', UM_distinctid='15d188be71d50-013c49b12ec14a-3f73035d-100200-15d188be71ffd') header = {'User-Agent': random.choice(user_agent_list)} proxies = {'http': ip} response = requests.get(fans_url, param, headers=header, cookies=cookies, proxies=proxies) page_json = response.json() # print(page_json['data']['list']) for item in page_json['data']['list']: if (int(item['years']) >= 20): mdtxt(int(item['years'])) saveTxt(int(item['years']), item) fansNums = fansNums + 1
##############################################################
def forSave(range_list): for page in range(range_list[0], range_list[1]): findFans('blogdevteam', str(page), ip) print('page', page,'记录完成 码龄20年以上粉丝数:', fansNums)
if __name__ == '__main__': ip = return_ip() header = {'User-Agent': random.choice(user_agent_list)} range_lists = [[1, 141], [142, 283], [284, 424], [425, 564], [565, 706]] pool = Pool(5) pool.map(forSave, range_lists) pool.close() pool.join()
复制代码



爬取结果

这些 21 年的用户不会是 csdn 建立时就存在的吧???



得出结论: csdn 官方博客粉丝中码龄 20 年以上的大佬有 33 位,而码龄在 21 年的有 7 位


呼,终于写完了,路漫漫其修远兮。其实爬虫的功能可以更加优秀,把我一开始的目标也实现,不过还得看自己学习的怎么样啦



发布于: 2021 年 04 月 01 日阅读数: 34
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
根据码龄来爬取CSDN博客粉丝