iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
2

前言

終於進到我們實作篇啦XD,前面其實一直有說要教大家實作Dcard,但是因為又想到很多前置教學沒有教到,所以一直延後,本篇小編會教大家如何下載Dcard文章中的圖片跟此文章連結,會結合前面所學,將連結跟圖片名稱寫入檔案中,方便大家查閱,而且一次下載的圖片也不會太少量。

工商時間

有鑑於怕大家覺得小編的文太無聊或是都會了,向大家推往一下我們團隊MeowMeow其他團員的文章!!
  1. 團長 飛飛 - 資訊安全大補帖
  2. 團員 阿褚 - 挑戰 Daily UI!
  3. 團員 HelloWorld - 資工人該知道的10件事情 與 在電腦硬體軟體遇到神奇經歷 分享
  4. 團員 Maple - 大二資工人-30天日記

Dcard爬蟲實作

  1. 程式碼撰寫邏輯
    1. 先以寵物版首頁將所以文章連結爬下來存到list裡,那就會考慮到瀏覽器往下滑換頁,所以要送一個GET
    2. 從list將連結一個一個取出來組合成正確的網址,並GET下來,尋找圖片的標籤
    3. 如果有圖片的標籤就在本地端新增檔案,並將圖片存檔
    4. 將每一個顯示在頁面是給使用者看得,都存到一個記事本中當作圖片目錄
  2. 先將Python套件import進來 requests BeautifulSoup json
    import requests
    from bs4 import BeautifulSoup
    import json
    
  3. 一開始需要先GET寵物版首頁,並使用BeautifulSoup處理成html樣式,還有開一個txt存目錄
    test = open("spider/pet/test.txt","w",encoding='UTF-8')
    
    p = requests.Session()
    url=requests.get("https://www.dcard.tw/f/pet")
    soup = BeautifulSoup(url.text,"html.parser")
    
  4. 將首頁文章的連結網址存入list中
    sel = soup.select("div.PostList_wrapper_2BLUM a.PostEntry_root_V6g0r")
    a=[]
    for s in sel:
        a.append(s["href"])
    url = "https://www.dcard.tw"+ a[2]
    
  5. 根據把首頁往下滑,發現網站會對server送一個GET請求下一個30篇文章
    for k in range(0,10):
        post_data={
            "before":a[-1][9:18],
            "limit":"30",
            "popular":"true"
        }
        r = p.get("https://www.dcard.tw/_api/forums/pet/posts",params=post_data, headers = { "Referer": "https://www.dcard.tw/", "User-Agent": "Mozilla/5.0" })
    
  6. 發現GET來的檔案格式是JSON,那小編比較不會處理JSON怎辦?可以把他轉成Python就好啦,並組合好網址放進list
    data2 = json.loads(r.text)
        for u in range(len(data2)):
            Temporary_url = "/f/pet/p/"+ str(data2[u]["id"]) + "-" + str(data2[u]["title"].replace(" ","-"))
            a.append(Temporary_url)
    
  7. 接下來就是將list裡的URL,GET網頁出來
    j=0
    q=0
    for i in a[2:]:
        url = "https://www.dcard.tw"+i
        j+=1
        print ("第",j,"頁的URL為:"+url)
        #file.write("temperature is {} wet is {}%\n".format(temperature, humidity))
        test.write("第 {} 頁的URL為: {} \n".format(j,url))
        url=requests.get(url)
        soup = BeautifulSoup(url.text,"html.parser")
    
  8. 運用BeautifulSoup查看是否有符合圖片的標籤,然後運用上次所學,將圖片存檔
    sel_jpg = soup.select("div.Post_content_NKEl9 div div div img.GalleryImage_image_3lGzO")
    for c in sel_jpg:
        q+=1
        print("第",q,"張:",c["src"])
        test.write("%\n""第 {} 張: {} \n".format(q,c["src"])) 
        pic=requests.get(c["src"])
        img2 = pic.content
        pic_out = open("spider/pet/"+str(q)+".png",'wb')
        pic_out.write(img2)
        pic_out.close()
    
  9. 記得將剛剛的txt目錄關檔,並寫一個爬蟲結束提醒自己
    test.close()
    print("爬蟲結束")
    
  10. 完整的程式碼(可改range將文章變多)
    #藉由首頁取得所有文章的URL
    import requests
    from bs4 import BeautifulSoup
    import json
    
    test = open("spider/pet/test.txt","w",encoding='UTF-8')
    
    
    p = requests.Session()
    url=requests.get("https://www.dcard.tw/f/pet")
    soup = BeautifulSoup(url.text,"html.parser")
    sel = soup.select("div.PostList_wrapper_2BLUM a.PostEntry_root_V6g0r")
    a=[]
    for s in sel:
        a.append(s["href"])
    url = "https://www.dcard.tw"+ a[2]
    
    for k in range(0,10):
            post_data={
                "before":a[-1][9:18],
                "limit":"30",
                "popular":"true"
            }
            r = p.get("https://www.dcard.tw/_api/forums/pet/posts",params=post_data, headers = { "Referer": "https://www.dcard.tw/", "User-Agent": "Mozilla/5.0" })
            data2 = json.loads(r.text)
            for u in range(len(data2)):
                Temporary_url = "/f/pet/p/"+ str(data2[u]["id"]) + "-" + str(data2[u]["title"].replace(" ","-"))
                a.append(Temporary_url)
    j=0 #為了印頁數
    q=0 #為了印張數
    for i in a[2:]:
        url = "https://www.dcard.tw"+i
        j+=1
        print ("第",j,"頁的URL為:"+url)
        #file.write("temperature is {} wet is {}%\n".format(temperature, humidity))
        test.write("第 {} 頁的URL為: {} \n".format(j,url))
        url=requests.get(url)
        soup = BeautifulSoup(url.text,"html.parser")
        sel_jpg = soup.select("div.Post_content_NKEl9 div div div img.GalleryImage_image_3lGzO")
        for c in sel_jpg:
            q+=1
            print("第",q,"張:",c["src"])
            test.write("%\n""第 {} 張: {} \n".format(q,c["src"])) 
            pic=requests.get(c["src"])
            img2 = pic.content
            pic_out = open("spider/pet/"+str(q)+".png",'wb')
            pic_out.write(img2)
            pic_out.close()
    
    test.close()
    print("爬蟲結束")
    
  11. 最後呈現應該會顯示以下,然後可以在本地端找到資料夾pet裡有很多圖片和目錄


    12. 最重要的提醒!!!
    • 一定要在本地端建立資料夾/spider/pet喔!!!! 不然第六行就會噴錯!!!

結語

程式碼有點長,所以有點不知道該怎麼教大家,所以如果有讀者對程式碼有問題的,都可以在底下留言,小編會一一的向大家說明,如果是覺得程式碼太冗長,小編盡力了,不要忘記通訊系的QQ,小編混口飯吃,大家鞭小力一點,當然如果有更簡潔的程式碼也歡迎交流!!
對了,其實這個爬蟲可以爬 Dcard寵物版 那就表示也可以爬其他各版,讓各位讀者自己去活用吧!

我絕對不會說,我最初才不是為了爬寵物版呢!是要爬西...

(此文章為教育使用,個人實作皆屬個人行為,本作者不負任何法律責任)


上一篇
Day-3 Python爬蟲小人生(3)
下一篇
Day-5 網路篇-WWW&HTTP
系列文
在資訊宅中打滾的通訊系生30
1
r567tw
iT邦新手 3 級 ‧ 2018-10-19 23:11:51

哈哈!
感謝大大出此文。

很久以前也是利用下班時間玩python,然後也是有試寫過在網頁上把圖片/影片抓回來
當時我使用的是‘urllib.request.urlretrieve(img_url, filename)'

當時忘了是用python2還是python3寫的,結果一直卡關~然後好像都噴那種類似SSL錯誤什麼之類的,害我昨天鐵人賽差點出不來哈哈XD,結果大大居然是再發一次request在取得request寫入檔案。真是有趣了! 我以為回傳的都是html+css+js等文字的說? 還是只有dcard這個網站適合這樣爬嗎?

Jayhom iT邦新手 5 級 ‧ 2018-10-20 00:04:02 檢舉

哈哈,不敢當大大
感謝你來看我的文

其實只有Dcard剛好有這條網址可以讓我這樣用,所以才可以再發一次來取得JSON,其他網站還要研究看看XD
code有點髒,可以自行修改

0
小非洲
iT邦新手 5 級 ‧ 2018-11-14 16:18:16

大大,請問一下
在第3點,打完會出現以下錯誤
FileNotFoundError: [Errno 2] No such file or directory: 'spider/pet/test.txt'
要如何解呢

thevid iT邦新手 5 級 ‧ 2019-02-14 16:51:30 檢舉

目錄下依序建立
python.py
spider
-spider
-Lpet
--Ltest.txt

0
liwei290341
iT邦新手 5 級 ‧ 2018-12-22 10:59:55

大大你好,我十月底的時候實測了您的程式碼,還是可用可以下載的,但在十二月開始,運行程式碼時就會跑出


IndexError: list index out of range


的Error;
不知道還有沒有解呢?

lebniz iT邦新手 5 級 ‧ 2019-06-22 22:28:24 檢舉

可以確認一下要抓的 html 的結構跟tag 的 class 名稱

0
tw19930419
iT邦新手 5 級 ‧ 2019-12-02 12:20:16

根據把首頁往下滑,發現網站會對server送一個GET請求下一個30篇文章
=> 想請問這段如何看出是GET,以及看出後接下來這段

for k in range(0,10):
    post_data={
        "before":a[-1][9:18],
        "limit":"30",
        "popular":"true"
    }
    r = p.get("https://www.dcard.tw/_api/forums/pet/posts",params=post_data, headers = { "Referer": "https://www.dcard.tw/", "User-Agent": "Mozilla/5.0" })

是如何得知這些資訊來發出請求呢?
我目前是用chrome的開發者工具去看,但看不太出什麼端倪。

我要留言

立即登入留言