1. 程式人生 > >虎撲《不冷笑話》爬蟲實戰,順帶說說最近學寫爬蟲的經歷(一)

虎撲《不冷笑話》爬蟲實戰,順帶說說最近學寫爬蟲的經歷(一)

前言

樓主16年畢業,工作內容目前主要以ETL開發為主。有一段時間逛知乎,經常看到有人分享一些資料分析的文章,比如美團上的點餐分析、豆瓣的評分分析,還有網易雲音樂熱評分析之類的。感覺這些文章都是有實打實的東西在,而且作者們的文筆也深得我心。後來也知道,這些資料大部分是用python爬蟲爬取的,所以我也開始斷斷續續在看相關的內容。本帖就是我在做其中一部分實戰的心路歷程了,權當記錄一下,水平較低莫怪。

1.起因

虎撲是廣大jrs的家園,步行街是這個家園裡最繁華的地段。據稱廣大jrs平均學歷985,步行街街薪30w起步。 大學時經舍友安利,開始瞭解虎撲,主要是看看NBA的一些資訊。 偶爾也上上這個破街,看看jrs虐虐狗,說說家長裡短等等,別的不說,jr們的三觀都是特別正的。 《不冷笑話》基本是我每天必看的帖子,感覺《不冷笑話》的幾位老夥計非常敬業,每天都會有高質量的輸出,帖子下的熱帖也很給力,福利滿滿。 正學python,突發奇想想把《不冷笑話》的圖都爬下來。

另外隨著我學習內容的增加,一個爬蟲也由最簡單的流水線式的結構,變為模組化的設計思路,之後又變為使用成熟的框架。下面就切入正題了。

2.經過

版本1:模組化的簡單實現

其實python的上手非常簡單,原因有兩個,python語言就很簡潔,python的包非常豐富。我在B站上跟著小甲魚的視訊沒學個十幾節課,就開始對照著別人最簡單的爬蟲例子在做了。 新手無非就是requests + BeautifulSoup,一個負責HTTP請求,一個負責HTML解析。就小規模爬蟲來講,主要時間還是用來定位爬取目標在頁面中的位置。所以,先看一下最low的爬蟲是什麼樣子。

# -*- coding: utf-8 -*-
import requests from bs4 import BeautifulSoup import os, time import re link = r'https://www.qiushibaike.com/pic/' r = requests.get(link) x = 1 soup = BeautifulSoup(r.text,'lxml') for content in soup.find_all(class_ = 'thumb'): xpath = content.find('img').get('src') image = requests.get('http:'
+ xpath) open('qiubai %d.jpg' % x,'wb').write(image.content) x += 1

除去匯入包和編碼宣告,十行程式碼就能寫一個爬蟲,用來爬取糗事百科網站上的圖片,並儲存成本地檔案。

實際上,一開始要準備爬取《不冷笑話》時,帖子地址的獲取是一個非常困擾我的問題。後來經過我長期觀察發現,《不冷笑話》總是在 虎撲NBA 的固定位置出現,所以我只要在這個頁面定位好就可以進去了。

這裡寫圖片描述

一開始我也是用最簡單的結構去做《不冷笑話》的爬蟲,但是又覺得這樣做好像是重用很低,所以,按照模組化的思路,劃定了幾個功能點:

  • 1、定位不冷笑話在首頁的位置,獲取連結和標題
  • 2、建立以標題命名的目錄,如果目錄存在,說明已下載,程式結束
  • 3、進入不冷笑話的介面,獲取正文中的圖片連結,存入列表
  • 4、獲取亮貼中的圖片連結,存入列表
  • 5、儲存圖片,根據傳入引數為正文或評論進行命名,區分圖片來源
  • 6、大功告成

最終基本都按照了功能劃分了模組,寫出來的是這個樣子的。

#-*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import os, time
import re

url = (r'https://nba.hupu.com/')

#獲取不冷笑話在首頁的位置,返回url和標題
def get_buleng_title_url(url):
    index_html = requests.get(url)
    index_html_s = BeautifulSoup(index_html.text,'lxml')
    main_street = index_html_s.find(class_ = 'gray-list main-stem max250')
    url_list = []
    url_name_list = []
    for dd in main_street.find_all('dd',limit = 5):
        url_list.append(dd.a.get('href'))
        url_name_list.append(dd.a.get_text())
    return [url_list[4],url_name_list[4]] 

#獲取不冷笑話正文中的圖片列表,利用set去重
def get_pic_url(buleng_list):
    pic_url_list = set()
    buleng_html = requests.get(buleng_list[0])
    buleng_html_s = BeautifulSoup(buleng_html.text,'lxml')
    buleng_content = buleng_html_s.find(class_='quote-content')
    for pic_url in buleng_content.find_all('img'):
        try:
            original_url = pic_url.get('data-original')
            pic_url_list.add(original_url.split('?')[0])
        except:
            pic_url_list.add(pic_url.get('src'))
    return pic_url_list

#建立以標題命名的資料夾,並返回是否建立成功
def makedir(buleng_list):
    path = ('E:\\pic\\buleng\\%s' % buleng_list[1])
    if os.path.exists(path):
        return 0
    else:
        os.makedirs(path)
        return path

#獲取亮貼中的圖片列表,set去重
def get_comment_pic_url(buleng_list):
    comment_pic_url_list = set()
    buleng_html = requests.get(buleng_list[0])
    buleng_html_s = BeautifulSoup(buleng_html.text,'lxml')
    buleng_comment = buleng_html_s.find(id='readfloor')
    for floor in buleng_comment.find_all('table'):
        for pic_url in floor.find_all('img'):           
            try:
                original_url = pic_url.get('data-original')
                comment_pic_url_list.add(original_url.split('?')[0])
            except:
                comment_pic_url_list.add(pic_url.get('src'))
    return comment_pic_url_list


#下載圖片,可下載gif、jpg、png格式
def download_pic(pic_url_list,path,pic_from = '正文'):
    a = 1
    for url in pic_url_list :
        if url.endswith('.gif'):
            pic = requests.get(url)
            with open((path+('\\%s-%s.gif' % (pic_from,a))),'wb') as f:
                f.write(pic.content)
                f.close
                print('下載一張%s動圖' % pic_from)
            a += 1
        if url.endswith('.jpg'):
            pic = requests.get(url)
            with open((path+('\\%s-%s.jpg' % (pic_from,a))),'wb') as f:
                f.write(pic.content)
                f.close
                print('下載一張%sjpg圖' % pic_from)
            a +=1
        if url.endswith('.png'):
            pic = requests.get(url)
            with open((path+('\\%s-%s.png' % (pic_from,a))),'wb') as f:
                f.write(pic.content)
                f.close
                print('下載一張%spng圖' % pic_from)
            a +=1

if __name__ == "__main__":
    buleng = get_buleng_title_url(url)
    path = makedir(buleng)
    if path != 0:
        pic_url_list = get_pic_url(buleng)
        comment_pic_url_list = get_comment_pic_url(buleng)
        download_pic(pic_url_list,path)
        download_pic(comment_pic_url_list,path,'評論')
    else:
        print('目錄已存在,等待虎撲更新')

版本2:模組化的簡單實現plus

後來我一想,反正都是獲取了主幹道所有的推薦貼,為啥不自定義要下載的帖子呢,這樣的話,這十幾個推薦貼想下哪個下哪個,不是功能更上一層樓了? 多虧了模組化的設計,博主略一沉吟,部分修改如下:

#獲取熱帖在首頁的位置,返回url和標題
def get_retie_title_url(url):
    index_html = requests.get(url)
    index_html_s = BeautifulSoup(index_html.text,'lxml')
    main_street = index_html_s.find(class_ = 'gray-list main-stem max250')
    url_list = []
    url_name_list = []
    for dd in main_street.find_all('dd',limit = 14):
        url_list.append(dd.a.get('href'))
        url_name_list.append(dd.a.get_text())
    return [url_list,url_name_list] 
    #return [url_list[4],url_name_list[4]]  原始碼對比 

#獲取熱帖正文中的圖片列表,利用set去重
def get_pic_url(retie_list,num): #新加num引數
    pic_url_list = set()
    retie_html = requests.get(retie_list[0][num-1])
    retie_html_s = BeautifulSoup(retie_html.text,'lxml')
    retie_content = retie_html_s.find(class_='quote-content')
    for pic_url in retie_content.find_all('img'):
        try:
            original_url = pic_url.get('data-original')
            pic_url_list.add(original_url.split('?')[0])
        except:
            pic_url_list.add(pic_url.get('src'))
    return pic_url_list

if __name__ == "__main__":
    retie = get_retie_title_url(url)
    a = 1
    for retie_title in retie[1]:
        print(a,'  ',retie_title)
        print('--------------------------------')
        a += 1
    num = int(input('請輸入要下載的熱帖排序(1-14)')) #獲取輸入序號
    if num < 1 or num > 14:
        print('不合法')
    else:
        path = makedir(retie[1][num-1])
        if path != 0:
            pic_url_list = get_pic_url(retie,num)
            comment_pic_url_list = get_comment_pic_url(retie,num)
            download_pic(pic_url_list,path)
            download_pic(comment_pic_url_list,path,'評論')
        else:
            print('目錄已存在,等待虎撲更新')

然後效果就是這樣啦

這裡寫圖片描述

3.總結

好了,今天的無干貨流水賬就先告一段落,欲知後事如何,且聽下回分解