Python3 爬蟲實戰 — 虎撲論壇步行街


  • 爬取時間: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 條數據:
01

【6x00】程序不足的地方

程序只能爬取前 10 頁的數據,因爲虎撲論壇要求從第 11 頁開始,必須登錄賬號才能查看,並且登錄時會有智能驗證,可以使用自動化測試工具 Selenium 模擬登錄賬號後再進行爬取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章