Python编写高质量知乎回答爬虫,快速获取答案
优采云 发布时间: 2023-03-09 18:13知乎是一个高质量的问答社区,里面蕴藏着大量的知识和经验,对于学习和研究都有很大的帮助。然而,要想获取其中的精华内容却不是一件容易的事情。今天,我将介绍如何用Python编写一个知乎回答爬虫,帮助你快速抓取高质量回答,让你在学习和研究中事半功倍。
1.确定目标
在开始编写爬虫之前,我们需要明确自己的目标。比如说,我们想要抓取某个话题下所有赞数超过1000的回答,并将其保存到本地文件中。这就是我们的目标。
2.分析页面结构
在确定了目标之后,我们需要分析页面结构,并找到我们需要的信息。对于知乎来说,我们可以通过浏览器开发者工具或者第三方工具(如SelectorGadget)来查看页面结构和元素属性。
3.获取页面内容
获取页面内容是爬虫的核心部分。我们可以使用Python中的requests库来发送HTTP请求,并使用BeautifulSoup库或者lxml库来解析HTML文档。在获取到页面内容之后,我们需要提取出所需信息并进行处理。
4.翻页处理
如果我们要抓取多页内容,就需要进行翻页处理。这可以通过修改URL参数或者使用Selenium库来实现。
5.存储数据
最后一步是存储数据。我们可以将数据保存到本地文件、数据库或者云端存储中。对于较小规模的数据集,可以使用csv、json等格式进行存储;对于较*敏*感*词*的数据集,则需要考虑使用数据库或者云端存储。
以上就是知乎回答爬虫的基本流程。接下来,我将详细介绍每个步骤需要注意的细节和具体实现方法。
1.确定目标
确定目标是爬虫编写过程中最重要的一步。在这一步中,我们需要明确以下几个问题:
-我们要抓取哪些信息?
-这些信息在页面中以什么形式呈现?
-我们要抓取哪些页面?
-如何判断一个回答是否符合要求?
假设我们想要抓取“Python”话题下所有赞数超过1000的回答,并将其保存到本地文件中。那么,我们需要明确以下几点:
-我们需要抓取回答标题、作者、发布时间、点赞数、评论数、回答内容等信息。
-这些信息在页面中以HTML标签和属性的形式呈现。
-我们需要抓取“5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers?71860c77c6745379b0d44304d66b6a13=1”至“5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers?71860c77c6745379b0d44304d66b6a13=n”的所有页面。
-我们只保留赞数超过1000的回答。
2.分析页面结构
分析页面结构是爬虫编写过程中不可或缺的一步。通过浏览器开发者工具(F12)或者第三方工具(如SelectorGadget),我们可以查看网页源码和元素属性,并找到所需信息所对应的HTML标签和属性。
对于知乎来说,每个回答都有一个唯一的data-entry-url属性值,因此可以通过该属性值来定位每个回答块:
```html
<div class="List-item" data-entry-url="/answer/123456789">
...
</div>
```
在每个回答块内部,包含了许多有用信息:
```html
<div class="ContentItem AnswerItem">
<meta itemprop="name" content="How to learn Python?">
<meta itemprop="author" content="John Doe">
<meta itemprop="datePublished" content="2023-03-09T08:00:00+08:00">
<meta itemprop="upvoteCount" content="2000">
<meta itemprop="commentCount" content="500">
<div class="RichContent">
...
</div>
</div>
```
通过查看源码和元素属性,我们可以得出以下结论:
-回答标题:位于`<meta itemprop="name">`标签内。
-作者:位于`<meta itemprop="author">`标签内。
-发布时间:位于`<meta itemprop="datePublished">`标签内。
-点赞数:位于`<meta itemprop="upvoteCount">`标签内。
-评论数:位于`<meta itemprop="commentCount">`标签内。
-回答内容:位于`<div class="RichContent">`标签内。
3.获取页面内容
获取页面内容是爬虫编写过程中最核心也最复杂的一步。在这一步中,我们需要发送HTTP请求并解析HTML文档,并从中提取出所需信息并进行处理。
首先,在Python代码中导入必要的库:
```python
import requests
from bs4 import BeautifulSoup
```
然后,在代码中定义一个函数用于获取单个页面上所有符合条件的回答:
```python
def get_answers(url):
headers ={
'User-Agent':'Mozilla/5.0(Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text,'lxml')
answers =[]
for answer in soup.find_all('div',{'class':'List-item'}):
upvote_count = answer.find('meta',{'itemprop':'upvoteCount'})['content']
if int(upvote_count)>= 1000:
title = answer.find('meta',{'itemprop':'name'})['content']
author = answer.find('meta',{'itemprop':'author'})['content']
publish_time = answer.find('meta',{'itemprop':'datePublished'})['content']
comment_count = answer.find('meta',{'itemprop':'commentCount'})['content']
content = answer.find('div',{'class':'RichContent'}).get_text()
answers.append({'title': title,'author': author,'publish_time': publish_time,
'upvote_count': upvote_count,'comment_count': comment_count,
'content': content})
return answers
```
该函数接受一个URL作为参数,并返回一个列表类型对象answers,其中包含了所需信息。函数首先发送HTTP请求并解析HTML文档;然后查找所有符合条件(即赞数超过1000)且回答块;最后提取出所需信息并保存到列表answers中。
4.翻页处理
如果我们想要抓取多页内容,则需要进行翻页处理。这可以通过修改URL参数或使用Selenium库来实现。
首先看第一种方法——修改URL参数:
```python
for i in range(1,n+1):
url =f'5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers?71860c77c6745379b0d44304d66b6a13={i}'
answers += get_answers(url)
```
其中n为总共要抓取多少页数据。
第二种方法——使用Selenium库:
```python
from selenium import webdriver
driver_path ='/path/to/chromedriver'
url ='5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers'
driver = webdriver.Chrome(executable_path=driver_path)
driver.get(url)
for i in range(1,n+1):
driver.execute_script(f'window.scrollTo(0, document.body.scrollHeight);')
time.sleep(2)
source_code = driver.71860c77c6745379b0d44304d66b6a13_source
soup = BeautifulSoup(source_code,'lxml')
answers += get_answers(98a5f537c46e6a2bcd1066ec72b9a612)
driver.quit()
```
该方法首先启动Chrome浏览器,并打开指定URL;然后通过JavaScript代码模拟滚动条向下滚动,并等待2秒钟;最后获取当前网页源码并解析HTML文档,并调用get_answers函数提取所需信息。
5.存储数据
最后一步是存储数据。对于小规模数据集(如少量回答),可以使用csv、json等格式进行存储;对于*敏*感*词*数据集,则应该考虑使用数据库或云端存储(如优采云)进行存储。
以csv格式为例,在Python代码中导入必要库并定义一个函数用于将数据保存为csv文件:
```python
import csv
def save_to_csv(data, filename):
with open(filename, mode='w', encoding='utf8') as f:
writer = csv.writer(f)
writer.writerow(['title','author','publish_time','upvote_count',
'comment_count','content'])
for item in data:
writer.writerow([item['title'], item['author'], item['publish_time'],
item['upvote_count'], item['comment_count'],
item['content']])
```
该函数接受两个参数:data为包含所需信息的列表对象;filename为保存文件名(含路径)。函数首先打开指定文件并创建一个csv.writer对象;然后写入列名行;最后逐行写入数据。
完整代码见下方:
```python
import requests
from bs4 import BeautifulSoup
import csv
def get_answers(url):
headers ={
'User-Agent':'Mozilla/5.0(Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text,'lxml')
answers =[]
for answer in soup.find_all('div',{'class':'List-item'}):
upvote_count = answer.find('meta',{'itemprop':'upvoteCount'})['content']
if int(upvote_count)>= 1000:
title = answer.find('meta',{'itemprop':'name'})['content']
author = answer.find('meta',{'itemprop':'author'})['content']
publish_time = answer.find('meta',{'itemprop':'datePublished'})['content']
comment_count = answer.find('meta',{'itemprop':'commentCount'})['content']
content = answer.find('div',{'class':'RichContent'}).get_text()
answers.append({'title': title,
'author': author,
'publish_time': publish_time,
'upvote_count': upvote_count,
'comment_count': comment_count,
'content': content})
return answers
def save_to_csv(data, filename):
with open(filename, mode='w', encoding='utf8') as f:
writer = csv.writer(f)
writer.writerow(['title',
'author',
"publish_time",
"upvote_count",
"comment_count",
"content"])
for item in data:
writer.writerow([item["title"],
item["author"],
item["publish_time"],
item["upvote_count"],
item["comment_count"],
item["content"]])
if __name__=='__main__':
answers_total=[]
#抓取前n页所有符合条件(即赞数超过1000)且回答块
n=10
# 方法1:修改url参数
# for i in range(1,n+1):
# url=f"5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers?71860c77c6745379b0d44304d66b6a13={i}"
# print("正在抓取第{}页...".format(i))
# answers=get_answers(url)
# print("已获取{}条记录".format(len(answers)))
# print("="*50)
# answers_total+=answers
# 方法2:使用selenium库
from selenium import webdriver
# 指定chromedriver路径
# driver_path='/Users/benjamin/Documents/chromedriver'
# url='5e056c500a1c4b6a7110b50d807bade5://www.zhihu.com/topic/19552832/top-answers'
# driver=webdriver.Chrome(executable_path=driver_path)
# driver.get(url)
# #模拟滚动条向下滚动n次
# for i in range(n):
# driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# time.sleep(2)
# source_code=driver.71860c77c6745379b0d44304d66b6a13_source
#1bbe243aab886fd2b14e7315537b9207=BeautifulSoup(source_code,'lxml')
# answers=get_answers(98a5f537c46e6a2bcd1066ec72b9a612)
# print("已获取{}条记录".format(len(answers)))
# print("="*50)
# answers_total+=answers
# driver.quit()