- 爬取時間:2019-10-12
- 爬取難度:★★☆☆☆☆
- 請求鏈接:https://bbs.hupu.com/bxj
- 爬取目標:爬取虎撲論壇步行街的帖子,包含主題,作者,發佈時間等,數據保存到 MongoDB 數據庫
- 涉及知識:請求庫 requests、解析庫 Beautiful Soup、數據庫 MongoDB 的操作
- 完整代碼:https://github.com/TRHX/Python3-Spider-Practice/tree/master/hupu
- 其他爬蟲實戰代碼合集(持續更新):https://github.com/TRHX/Python3-Spider-Practice
- 爬蟲實戰專欄(持續更新):https://itrhx.blog.csdn.net/article/category/9351278
【1x00】循環爬取網頁模塊
觀察虎撲論壇步行街分區,請求地址爲:https://bbs.hupu.com/bxj
第一頁:https://bbs.hupu.com/bxj
第二頁:https://bbs.hupu.com/bxj-2
第三頁:https://bbs.hupu.com/bxj-3
不難發現,每增加一頁,只需要添加 -頁數
參數即可,最後一頁是第 50 頁,因此可以利用 for 循環依次爬取,定義一個 get_pages()
函數,返回初始化 Beautiful Soup 的對象 page_soup,方便後面的解析函數調用
雖然一共有 50 頁,但是當用戶訪問第 10 頁以後的頁面的時候,會要求登錄虎撲,不然就沒法查看,而且登錄時會出現智能驗證,所以程序只爬取前 10 頁的數據
def get_pages(page_url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
response = requests.get(url=page_url, headers=headers)
page_soup = BeautifulSoup(response.text, 'lxml')
return page_soup
if __name__ == '__main__':
for i in range(1, 11):
url = 'https://bbs.hupu.com/bxj-' + str(i)
soup = get_pages(url)
【2x00】解析模塊
使用 Beautiful Soup 對網頁各個信息進行提取,最後將這些信息放進一個列表裏,然後調用列表的 .append()
方法,再將每條帖子的列表依次加到另一個新列表裏,最終返回的是類似於如下形式的列表:
[['帖子1', '作者1'], ['帖子2', '作者2'], ['帖子3', '作者3']]
這樣做的目的是:方便 MongoDB 依次儲存每一條帖子的信息
def parse_pages(page_soup):
data_list = []
all_list = page_soup.find('ul', class_='for-list')
post_list = all_list.find_all('li')
# print(result_list)
for post in post_list:
# 帖子名稱
post_title = post.find('a', class_='truetit').text
# print(post_title)
# 帖子鏈接
post_url = 'https://bbs.hupu.com' + post.find('a', class_='truetit')['href']
# print(post_url)
# 作者
author = post.select('.author > a')[0].text
# print(author)
# 作者主頁
author_url = post.select('.author > a')[0]['href']
# print(author_url)
# 發佈日期
post_date = post.select('.author > a')[1].text
# print(post_date)
reply_view = post.find('span', class_='ansour').text
# 回覆數
post_reply = reply_view.split('/')[0].strip()
# print(post_reply)
# 瀏覽量
post_view = reply_view.split('/')[1].strip()
# print(post_view)
# 最後回覆時間
last_data = post.select('.endreply > a')[0].text
# print(last_data)
# 最後回覆用戶
last_user = post.select('.endreply > span')[0].text
# print(last_user)
data_list.append([post_title, post_url, author, author_url, post_date, post_reply, post_view, last_data, last_user])
# print(data_list)
return data_list
【3x00】MongoDB 數據儲存模塊
首先使用 MongoClient()
方法,向其傳入地址參數 host 和 端口參數 port,指定數據庫爲 hupu
,集合爲 bxj
將解析函數返回的列表傳入到儲存函數,依次循環該列表,對每一條帖子的信息進行提取並儲存
def mongodb(data_list):
client = MongoClient('localhost', 27017)
db = client.hupu
collection = db.bxj
for data in data_list:
bxj = {
'帖子名稱': data[0],
'帖子鏈接': data[1],
'作者': data[2],
'作者主頁': data[3],
'發佈日期': str(data[4]),
'回覆數': data[5],
'瀏覽量': data[6],
'最後回覆時間': str(data[7]),
'最後回覆用戶': data[8]
}
collection.insert_one(bxj)
【4x00】完整代碼
# =============================================
# --*-- coding: utf-8 --*--
# @Time : 2019-10-12
# @Author : TRHX
# @Blog : www.itrhx.com
# @CSDN : https://blog.csdn.net/qq_36759224
# @FileName: hupu.py
# @Software: PyCharm
# =============================================
import requests
import time
import random
from pymongo import MongoClient
from bs4 import BeautifulSoup
def get_pages(page_url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
response = requests.get(url=page_url, headers=headers)
page_soup = BeautifulSoup(response.text, 'lxml')
return page_soup
def parse_pages(page_soup):
data_list = []
all_list = page_soup.find('ul', class_='for-list')
post_list = all_list.find_all('li')
# print(result_list)
for post in post_list:
# 帖子名稱
post_title = post.find('a', class_='truetit').text
# print(post_title)
# 帖子鏈接
post_url = 'https://bbs.hupu.com' + post.find('a', class_='truetit')['href']
# print(post_url)
# 作者
author = post.select('.author > a')[0].text
# print(author)
# 作者主頁
author_url = post.select('.author > a')[0]['href']
# print(author_url)
# 發佈日期
post_date = post.select('.author > a')[1].text
# print(post_date)
reply_view = post.find('span', class_='ansour').text
# 回覆數
post_reply = reply_view.split('/')[0].strip()
# print(post_reply)
# 瀏覽量
post_view = reply_view.split('/')[1].strip()
# print(post_view)
# 最後回覆時間
last_data = post.select('.endreply > a')[0].text
# print(last_data)
# 最後回覆用戶
last_user = post.select('.endreply > span')[0].text
# print(last_user)
data_list.append([post_title, post_url, author, author_url, post_date, post_reply, post_view, last_data, last_user])
# print(data_list)
return data_list
def mongodb(data_list):
client = MongoClient('localhost', 27017)
db = client.hupu
collection = db.bxj
for data in data_list:
bxj = {
'帖子名稱': data[0],
'帖子鏈接': data[1],
'作者': data[2],
'作者主頁': data[3],
'發佈日期': str(data[4]),
'回覆數': data[5],
'瀏覽量': data[6],
'最後回覆時間': str(data[7]),
'最後回覆用戶': data[8]
}
collection.insert_one(bxj)
if __name__ == '__main__':
for i in range(1, 11):
url = 'https://bbs.hupu.com/bxj-' + str(i)
soup = get_pages(url)
result_list = parse_pages(soup)
mongodb(result_list)
print('第', i, '頁數據爬取完畢!')
time.sleep(random.randint(3, 10))
print('前10頁所有數據爬取完畢!')
【5x00】數據截圖
一共爬取到 1180 條數據:
【6x00】程序不足的地方
程序只能爬取前 10 頁的數據,因爲虎撲論壇要求從第 11 頁開始,必須登錄賬號才能查看,並且登錄時會有智能驗證,可以使用自動化測試工具 Selenium 模擬登錄賬號後再進行爬取。