首先声明,这次爬虫只做为测试使用。拿知乎练练手而已,不会做为其它用途。
正文开始,假如我要拿到用户如下的信息。
通过request请求其实还是比较容易的。直接 request.get 用户主页url 。返回的源码里面就有用户的详细资料信息,内容均到JavaScript代码里面。如下图。
通过正则表达式就能轻易的得到了。
问题来了,如何批量获取知乎用户呢?
我们第一反应肯定是,通过一个页面里面存在的其它用户的主页地址来获取多个页面。这样下去就能批量获取了。通过关注者或者被关注者?
想法是很好的,但是我发现 请求 被关注者信息的request请求头里面有一个参数,一直都是随机的。需要逆向分析js代码,找到规律,才能成功提交。但是这是很难的(至少我不会)
知乎在反爬方面做得好就是在这里。之前还是没有的。
下面到了解决问题的方案。
我采用的是selenium,我们第一反应肯定是,控制浏览器直接获取页面来得到关注者或者被关注者的信息。
但是你在知乎未登录的情况下,用selenium页面上根本就没有其它用户的信息。
回答里面没有,提问,文章,专栏想法,全部都是为空(因为知乎检测到了你是测试浏览器)。最后只能从动态入手。
有了这个想法,我写出了如下代码。
from concurrent.futures.thread import ThreadPoolExecutor
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import Chrome
from lxml import etree
opt=Options()
opt.add_argument("--headless")
wait_data = set()
old_data=set()
#获取新的url
def get_moreUrl(url):
web = Chrome("D:\chromedriver.exe", options=opt)
web.get(url)
html = etree.HTML(web.page_source)
web.close()
divs=html.xpath('//*[@id="Profile-activities"]/div[2]/div')
for div in divs:
href=div.xpath('./div[2]/div/div[1]/div[1]/div/div/div[1]/span/div/div/a/@href')
if href :
new_href = "https:" + href[0]
if not old_data.__contains__(new_href):
wait_data.add(new_href)
print(new_href)
#获取页面详细信息
def get_data(url):
web = Chrome("D:\chromedriver.exe", options=opt)
web.get(url)
web.find_element_by_xpath("/html/body/div[4]/div/div/div/div[2]/button").click()
html = etree.HTML(web.page_source)
name=html.xpath('//*[@id="ProfileHeader"]/div/div[2]/div/div[2]/div[1]/h1/span/text()')[0]
num = html.xpath('//*[@id="root"]/div/main/div/meta[6]/@content')[0]
answer_num=html.xpath('//*[@id="root"]/div/div[2]/header/div[2]/div/div/ul/li[2]/a/span/text()')[0]
agree_num=html.xpath('//*[@id="root"]/div/main/div/meta[4]/@content')[0]
like_num=html.xpath('//*[@id="root"]/div/main/div/meta[5]/@content')[0]
web.close()
list=[url,name,num,answer_num,agree_num,like_num]
print(list)
if __name__ == '__main__':
wait_data.add("https://www.zhihu.com/people/system-out-99")
with ThreadPoolExecutor(10) as t:
while True:
if wait_data.__len__()>0:
url = wait_data.pop()
old_data.add(url)
t.submit(get_moreUrl,url)
t.sumbmit(get_data,url)
其实代码并不难,我觉得这个思路过程还是最重要的。虽然selenium效率并不高。但是加上线程池效率也是很客观了。1分钟几十条还是可行叭。
如果有大佬在代码上能有什么提高效率的建议。欢迎和我交流一下。
最后我的公众号: 爬虫代写
欢迎关注。