前言
继上一篇模拟用户登录成功后,那么我们能够以内部成员访问一些游客不能访问的内容了,其中便有此次项目中想要爬取的版块——鹊桥板块。
鹊桥(PieBridge)版旨在为北大在校学生、校友及亲人朋友提供一个包容、和谐、自由的寻找伴侣的平台。
板块中发布了许多交友贴(列表格式),那么把这些列表信息爬取下来,保存在MongoDB中。
一、分析页面
帖子列表
查看元素,找到列表的特征,所有的帖子信息显示在 class="list-item-topic list-item"
中
通过BeautifulSoup的findall方法,找到所有的list
单个帖子
然后遍历list,分析单个列表的内容,我们需要抓取url
, id
, title
,author_name
,publish_time
,reply_num
,last_reply_name
,last_reply_time
.
下一页处理
分析页面跳转栏页面,所有页面标签显示在 class="paging-button n"
中
-
如何找到下一页的url?
找到
class="paging-input-wrapper"
输入框标签,该标签的兄弟节点(上一个)即为下一页标签,循环遍历,拿到所有页面的列表数据
-
如何判断爬取到最后一页?
同样是找到输入框标签的兄弟节点(上一个),如果该标签
class="paging-button n active"
,即为爬取到最后一页
二、代码实现
用户登录已在上一章实现,本章实现爬取鹊桥板块的列表信息
- 主体
url = 'https://bbs.pku.edu.cn/v2/thread.php?bid=167&mode=topic&page=1'
base_url = 'https://bbs.pku.edu.cn/v2/'
def main():
global url
# 连接MongoDB数据库
db = connectDB()
# 创建表
collection = db['PieBridge']
# 获取 登录session
session = get_session()
while True:
# 获取页面
html = get_html(session, url)
print('已爬取页面:' + url)
# 分析页面 返回下一页url
url = parse_html(html, collection)
if url is None:
break
if __name__ == '__main__':
main()
-
数据库连接
# 数据库连接 def connectDB(): client = MongoClient('localhost', 27017) # 建库 db = client['PieBridge'] return db
-
获取页面
def get_html(session, url): if session is not None: # session 请求主页 登录cookie已保存在session中 response = session.get(url, headers=headers) return response.text
-
分析页面
def parse_html(html,collection): while True: # 下一页的前缀 next_base_url = 'https://bbs.pku.edu.cn/v2/thread.php' soup = BeautifulSoup(html, 'lxml') # 获取页面 帖子列表 items = soup.find_all(class_='list-item-topic list-item') # 遍历列表 for item in items: # 逐个分析 获取想要的数据 a = item.find(class_='link').get('href') url = base_url+a id = item.find(class_='id l').text title = item.find(class_='title l limit').text author_name = item.find(class_='author l').find(class_='name limit').text publish_time = item.find(class_='author l').find(class_='time').text reply_num = item.find(class_='reply-num l').text last_reply_name = item.find(class_='reply-num l').find_next_sibling(class_='author l').find(class_='name limit').text last_reply_time = item.find(class_='reply-num l').find_next_sibling(class_='author l').find(class_='time').text detail = {'_id': id, 'url':url, 'title': title, 'author_name': author_name, 'publish_time': publish_time, 'reply_num': reply_num, 'last_reply_name': last_reply_name, 'last_reply_time': last_reply_time} # 向表中插入数据 save2mongo(collection, detail) # details.append(detail) # 判断是否是最后一个页面 previous_class = ' '.join(soup.find('div', class_='paging-input-wrapper').find_previous_sibling().attrs['class']) if previous_class=='paging-button n active': break # 下一页 next_url =next_base_url+soup.find('div',class_='paging-input-wrapper').find_previous_sibling(class_='paging-button n').find(class_='link').get('href') return next_url return None
-
数据存储
def save2mongo(collection, detail): try: # 保存 # collection.insert(detail) collection.save(detail) except DuplicateKeyError: raise DuplicateKeyError except Exception as e: raise e
三、结果
程序爬取结果,一共251页
通过MongoDB工具,查看库中的详细数据
数据库详细信息,一共5002条数据
下一章,爬取单个帖子中的详细内容