Python爬取知乎盐选专栏热榜实例 | 您所在的位置:网站首页 › 盐选会员涨价 › Python爬取知乎盐选专栏热榜实例 |
背景
大家好。我,在被一个抖机灵答案吊足胃口、迫不得其充值了知乎盐选会员之后,越想越觉得抓心挠肝的亏。 我并不是说我不愿意为知识付费。事实上,我为7点jj氪金不少,但在知乎花9块钱看一个故事结局,总让我有一种背叛无产阶级的感觉。 于是,我,一个爬虫经验仅限于爬7点爽文和jj虐恋的无产阶级同志,决定尝试挑战自我,爬一下知乎盐选热榜。 榜单目录爬取首先,考虑将热榜的榜单爬取下来。也就是取得一个榜单的目录。 知乎盐选榜单网址: https://www.zhihu.com/xen/market/ranking-list/salt 但点进去就会发现,这是一个动态加载的页面,没有办法一次性爬取全部目录。 随后,发现在往下拉时,会返回一个包。里面的Request URL形式如下: 连接中的20/20是变化的。 https://api.zhihu.com/market/rank_list?type=hottest&sku_type=salt_all&limit=20&offset=20 具体爬取代码如下: 1234567891011121314151617181920212223242526272829303132333435363738import requests import re import json import jsonpath import os import csv import pandas as pd from retrying import retry from bs4 import BeautifulSoup from w3lib.html import remove_tags from collections import defaultdict cookie = '/你的cookie/' headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36', 'Cookie':cookie} url = 'https://api.zhihu.com/market/rank_list?type=hottest&sku_type=salt_all&limit=1000&offset=0' r = requests.get(url, headers = headers) html = r.content.decode() bsobj = BeautifulSoup(html, 'html.parser') a = json.loads(html) title = jsonpath.jsonpath(a,"$..title") author = jsonpath.jsonpath(a,"$..author") media_type = jsonpath.jsonpath(a,"$..media_type") button_text = jsonpath.jsonpath(a,"$..button_text") data0 = {'名称':title, '作者':author, '类型':media_type, '价格':button_text} data1 = pd.DataFrame(data = data0) # 查看爬取得到的目录 print(data1) # 输出目录文件 outputpath='./zhihu_concent.xlsx' data1.to_excel(outputpath,index=False, header=True)随后得到一份目录.xlsx文件。 获得作品链接得到目录显然是不够的,我们还需要爬取具体的作品内容。首先尝试从榜单页面得到跳转链接。 但是这就必须要解决刚刚遇到的问题——如何面对动态加载的界面? 考虑使用seleniu。 1pip3 install seleniu在Scripts目录下安装Chrome驱动器之后,开始继续爬取。 P.S.值得注意的是,下面只保留“盐选专栏”的链接,其他电子书和音频的链接直接删除。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152# 正儿八经开始爬取盐选专栏链接 from selenium import webdriver from lxml import etree import time import requests import re import json import jsonpath import os import csv from bs4 import BeautifulSoup cookie = '/你的cookie/' headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36', 'Cookie':cookie} urls = 'https://www.zhihu.com/xen/market/ranking-list/salt' # 使用selenium模拟人为访问页面,获取数据 def spider_jd(url): # ChromeOptions() 函数中有谷歌浏览器的一些配置 options = webdriver.ChromeOptions() # 告诉谷歌这里用的是无头模式 options.add_argument('headless') # 创建谷歌浏览器对象 driver = webdriver.Chrome() # 打开谷歌浏览器,进入指定网址的页面 driver.get(url) # 模拟10次下拉页面动作,是动态页面加载 for i in range(0,10): driver.execute_script("window.scrollTo(0,document.body.scrollHeight);") # 停顿2秒等待页面加载完毕(必须留有页面加载的时间,否则部分浏览器获得的源代码会不完整。) time.sleep(2) # 相当于 request.get(url, headers=header) source = driver.page_source bsobj = BeautifulSoup(source, 'html.parser') a = bsobj.find('div', attrs={'class': 'App-wrap-rM9XT'}) links= [] for k in a.find_all('a', attrs = {'class':'ProductCell-root-3LLcu RankingListItem-productCell-o4KL2'}): link = k['href'] # 只保存专栏(删除音频、电子书形式的盐选) if link[:51] == 'https://www.zhihu.com/xen/market/remix/paid_column/': links.append(link) driver.close() # 爬取完毕关闭浏览器 return links 12# 调用上述函数,得到专栏盐选的URL article_link = spider_jd(urls) 盐选专栏爬取我在这一步首先尝试了利用selenium进行帐号登录,然而失败了。 12345678910111213141516171819202122232425# 失败实例 url = article_link[0] driver = webdriver.Chrome() driver.get(url) login_button = driver.find_element_by_class_name('ShelfTopNav-login-p5mr5') login_button.click() time.sleep(1) login_tag = driver.find_element_by_class_name('LoginActions-actions-aKPz7') login_tag.click() time.sleep(1) username = driver.find_element_by_name('username') username.send_keys('/你的帐号/') time.sleep(1) password = driver.find_element_by_name('password') password.send_keys('/你的密码/') time.sleep(1) # 具体报错的就是这一步 login_submit = driver.find_element_by_class_name('Button SignFlow-submitButton Button--primary Button--blue') login_submit.click()具体的报错是: 123error: {code: 10001, message: "10001:请求参数异常,请升级客户端后重试"} code: 10001 message: "10001:请求参数异常,请升级客户端后重试"查看具体的请求信息得到: 1Failed to load resource: the server responded with a status of 403 ()所以是服务器拒绝我访问了。我其实没太搞懂为什么会这样,但是通过查阅资料以及思维推理,我觉得应该是服务器反Selenium爬虫机制。 我到处找应该怎么办,然后找到了一个看起来有些靠谱的答案: https://zhidao.baidu.com/question/751432606829473612.html 于是我打开百度,搜索“selenium接管chrome”。 于是我找到了这篇文章: https://www.cnblogs.com/pu369/p/12407996.html 就上述教程我进行的具体的操作简单总结如下: 将chrome.exe的目录添加到环境变量 打开cmd,在命令行中输入命令:chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\AutomationProfile" 此时会打开一个浏览器页面,我们把它当成一个已存在的浏览器,于是我们就要接管上面的浏览器 用python运行下面的代码: 12345678from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") chrome_driver = "chromedriver.exe" driver = webdriver.Chrome(chrome_driver, chrome_options=chrome_options) print(driver.title) driver.get("https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html") 此时你就已经接管了刚才那个浏览器,就比如说你刚才大概了百度首页,那么运行上述代码,就会print:百度一下,你就知道~喵了个咪的然后我试着按照之前那种点点点的方式,再在接管了的浏览器里面试图登录,又失败了。不仅失败了,我还在F12里面看到了知乎前端的招募广告。我能说什么?无产阶级永不认输呗。我不能技术性地登录我还不能扫码登进去吗我,呵呵。 于是我就扫码登陆了。 之后的过程枯燥乏味,无非就是仗着自己盐选会员的身份胡作为非。主要内容就是将每个专栏的章节合并放进一个txt。 代码如下 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081from selenium import webdriver from selenium.webdriver.chrome.options import Options import os import time from w3lib.html import remove_tags chrome_options = Options() chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") browser = webdriver.Chrome(chrome_driver, chrome_options=chrome_options) for i in range(len(article_link)): url = article_link[i] browser.get(url) time.sleep(3) source = browser.page_source bsobj = BeautifulSoup(source, 'html.parser') # 获得书名 a = bsobj.find('div', attrs={'class': 'AlbumColumnMagazineWebPage-title-wN4vV'}) book_title = remove_tags(str(a)) print(book_title) # 获得状态 a = bsobj.find('div', attrs={'class': 'SectionCount-root-8G3SV AlbumColumnMagazineWebPage-sectionCount-a2s6F'}) book_status = remove_tags(str(a)) print(book_status) # 写出文件(空文件) srcFile = '知乎/title.txt' dstFile = '知乎/'+ '【' + book_status + '】' + book_title + '.txt' with open('知乎/title.txt',"w",encoding='utf-8') as f: f.write('【' + book_status + '】' + '《' + book_title + '》' + '\n') f.write('\n') os.rename(srcFile,dstFile) # 获得目录 article_id = article_link[i].replace('https://www.zhihu.com/xen/market/remix/paid_column/', '') content_js = 'https://api.zhihu.com/remix/well/' + article_id + '/catalog?' r = requests.get(content_js, headers = headers) html = r.content.decode() a = json.loads(html) chapter_link = jsonpath.jsonpath(a, "$..url") # 获得章节的id chapter_id = [] for i in range(len(chapter_link)): chapter_id_temp = str(chapter_link[i]).replace('https://www.zhihu.com/market/manuscript?business_id=','').replace(article_id,'').replace('&track_id=', '').replace('&sku_type=paid_column','') chapter_id.append(chapter_id_temp) for j in range(len(chapter_link)): # 生成对应章节的url url = 'https://www.zhihu.com/market/paid_column/' + article_id + '/section/' + chapter_id[j] print(url) browser.get(url) time.sleep(2) source = browser.page_source bsobj = BeautifulSoup(source, 'html.parser') # 获得章节题目 title = bsobj.find('h1', attrs={'class': 'ManuscriptTitle-root-vhZzG'}) title = remove_tags(str(title)) # 获得正文 a = bsobj.find('div', attrs={'class': 'ManuscriptIntro-root-ighpP'}) b = remove_tags(str(a)) with open(dstFile,"a",encoding='utf-8') as f: f.write('第' + str(j+1) + '章·' + title + '\n') f.write(' ' + '\n') f.write(b + '\n') f.close()至此,知乎盐选热榜爬取完毕。 因为我爬虫技术并不是很熟练,代码写得也不是很漂亮。如果看到这篇文章的老师同学们有什么意见或者建议,欢迎联系我。谢谢啦! |
CopyRight 2018-2019 实验室设备网 版权所有 |