Python系列之七_抓知乎收藏夹
当我们在知乎上看到一个有趣的收藏夹时,想把里面所有的内容都抓下来,这时我们可以写一个Python程序。
我们发现知乎收藏夹的URL是有规律的:https://www.zhihu.com/collection/27109279?page=1
下一页page就等于2,依次递增,这个收藏夹共有77页。
首先我们的思路就是把每一页的HTML源代码先抓下来,然后把该页中的问题和答案都找出来。
通过查看HTML代码,我们发现问题部分的HTML代码长这样:
<h2 class="zm-item-title"><a target="_blank" href="/question/38627388">开车的人和不开车的人思维有什么区别?</a></h2>
而答案部分的HTML长这样:
<div class="zm-item-rich-text expandable js-collapse-body" data-resourceid="7658289" data-action="/answer/content" data-author-name="泰姆雷" data-entry-url="/question/38627388/answer/124188978">
<textarea hidden class="content">开车之后明白了一个道理:你能横穿马路跑过去,不是因为你跑得快,而是过来的车都踩了刹车。</textarea>
<div class="zh-summary summary clearfix">
开车之后明白了一个道理:你能横穿马路跑过去,不是因为你跑得快,而是过来的车都踩了刹车。
<a href="/question/38627388/answer/124188978" class="toggle-expand">显示全部</a>
</div>
答案部分有两处都包含了答案,但经过仔细观察,有一处是完整的答案,放在一个textarea中,平时是隐藏的;另一处只显示了答案的一部分,只有点击“显示全部”时,才显示完整答案。
因此我们理因选择完整答案,即textarea中的内容。
可以采用BeautifulSoup的select()功能,该功能可以按照指定规则从HTML代码中找出符合规则的所有标签,返回的一个列表。
例如:
soup = BeautifulSoup(html);
list1 = soup.select('a'); # 这是标签选择器,可以按照标签名称来选择
list2 = soup.select('.red'); # 这是类选择器,可以按照类名称来选择
list3 = soup.select('#div1'); # 这是ID选择器,可以按照ID来选择
list4 = soup.select('p.red'); # 组合应用
list5 = soup.select('p > a'); # p标签包含下级a标签
总之,select()选择器非常像CSS中的样式选择器,有标签选择器、类选择器、ID选择器等。
分析一下,怎么找出所有的问题呢?
<h2 class="zm-item-title"><a target="_blank" href="/question/38627388">开车的人和不开车的人思维有什么区别?</a></h2>
应该这么写:list1 = soup.select('h2.zm-item-title > a');
怎么找出所有的答案呢?
<textarea hidden class="content">开车之后明白了一个道理:你能横穿马路跑过去,不是因为你跑得快,而是过来的车都踩了刹车。</textarea>
应该这么写:list2 = soup.select('textarea.content');
当取得一页上的问题和答案列表后,只要依次将它们写到一个文本文件中即可。
我还给问题编了序号,最后是完整代码:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib
from bs4 import BeautifulSoup
# 为了解决向文本文件中写入中文内容报错,需导入这个库
import sys
# 以下两句是为了解决向文本文件中写入中文内容报错而加的
reload(sys)
sys.setdefaultencoding('UTF-8')
# 打开文件
f = open('E:/tmp/file.txt', 'w')
n = 1 # 问题序号
for page_no in range(1, 77):
url = 'https://www.zhihu.com/collection/27109279?page=%d' % page_no
page = urllib.urlopen(url)
soup = BeautifulSoup(page)
questions = soup.select('h2.zm-item-title > a')
answers = soup.select('textarea.content')
for i in range(len(questions)):
f.write('\n%d. %s\n' % (n, questions[i].string))
f.write('答:%s\n' % answers[i].string)
n += 1
f.close()