close

Python Django 實作(二) 爬蟲並分頁顯示資料 

 

本次練習包含以下項目

  1. 安裝爬蟲需要用到的套件
  2. 建立專案
  3. 分析 json 資料並分頁顯示
  4. 分析網頁資料並分頁顯示

 

 

 

 

一、安裝爬蟲需要用到的套件:

1.安裝 BeatuifulSoup4 套件

2.安裝 requests 套件

101.JPG

103.JPG

 

pip install BeatuifulSoup4

pip install requests

 

 

二、建立專案:

  1. 建立一個名為 crawler 的專案
  2. 建立名為 crawlerapp 的 App 
  3. 建立 templates 目錄、static 目錄
  4. 建立makemigrations 資料檔,並利用 migrate 將模型與資料庫同步
  5. 完成<setting.py>的設定

 

102.JPG

 

三、分析 json 資料並顯示:

這次使用的範例是政府開放資料平台的 動物認領養json

105.JPG

1.分析json

由於為了顯示單筆資料,所以會將元素加到串列中取用

接著將依照以下步驟進行:

  1. 導入分析需要用到的套件
  2. 連接網址
  3. 分析json 
  4. 建立空串列
  5. 將元素添加入串列
import json
import requests
res = requests.get('http://data.coa.gov.tw/Service/OpenData/AnimalOpenData.aspx') #連接網址
ress = res.text
jd = json.loads(ress)  #分析json

animal_place=[]  #建立空串列
animal_kind=[]
animal_sex=[]
animal_bodytype=[]
animal_age=[]
album_file=[]
shelter_name=[]
shelter_address=[]
shelter_tel=[]

for item in jd:  #將元素添加入串列
    animal_place.append(item['animal_place'])
    animal_kind.append(item['animal_kind'])
    animal_sex.append(item['animal_sex'])
    animal_bodytype.append(item['animal_bodytype'])
    animal_age.append(item['animal_age'])
    album_file.append(item['album_file'])
    shelter_name.append(item['shelter_name'])
    shelter_address.append(item['shelter_address'])
    shelter_tel.append(item['shelter_tel'])


 

2.顯示單筆資料

在 <views.py> 中建立一個名為 crawler 的自訂函數

def crawler(request):
    res = requests.get('http://data.coa.gov.tw/Service/OpenData/AnimalOpenData.aspx') #連接網址
    ress = res.text
    jd = json.loads(ress)  #分析json


    animal_place=[]  #建立空串列
    animal_kind=[]
    animal_sex=[]
    animal_bodytype=[]
    animal_age=[]
    album_file=[]
    shelter_name=[]
    shelter_address=[]
    shelter_tel=[]


    for item in jd:  #將元素添加入串列
        animal_place.append(item['animal_place'])
        animal_kind.append(item['animal_kind'])
        animal_sex.append(item['animal_sex'])
        animal_bodytype.append(item['animal_bodytype'])
        animal_age.append(item['animal_age'])
        album_file.append(item['album_file'])
        shelter_name.append(item['shelter_name'])
        shelter_address.append(item['shelter_address'])
        shelter_tel.append(item['shelter_tel'])

    return render(request,"crawler.html",locals())

創建一個名為 <crawler.html> 的模版

這邊調用串列的第一筆資料(第0項)

但是這邊不同於python語法的 "串列[0]"

而要使用 "串列.0" 的方式來顯示資料

 

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>顯示第一筆資料</title>
</head>
<body>
    <h2>顯示 Django json單筆資料 </h2>

    動物的實際所在地: {{animal_place.0}}  <br  />
    動物的類型: {{animal_kind.0}}  <br  />
    動物性別: {{animal_sex.0}}  <br  />
    動物體型: {{animal_bodytype.0}}  <br  />
    動物年紀: {{animal_age.0}}  <br  />
    動物所屬收容所名稱: {{shelter_name.0}}  <br  />
    圖片: <br  />
    <img src="{{album_file.0}}">      <br  />
    地址: {{shelter_address.0}}  <br  />
    聯絡電話: {{shelter_tel.0}}  <br  />





</body>
</html>

 

 

在<urls.py>添加crawler的路徑,並到瀏覽器執行:

104.JPG

 

3.顯示多筆資料

在 <views.py> 中建立一個名為 crawlerall 的自訂函數

由於多筆資料可以直接使用for迴圈來顯示,因此不用將元素加入串列

def crawlerall(request):
    res = requests.get('http://data.coa.gov.tw/Service/OpenData/AnimalOpenData.aspx')
    ress = res.text
    jd = json.loads(ress)

    return render(request,"crawlerall.html",locals())

創建一個名為 <crawlerall.html> 的模版

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>顯示所有資料</title>
</head>
<body>
    <h2>顯示 json 所有資料</h2>
    <table border="3" cellpadding="2" cellspacing="2">
        <th>動物的實際所在地</th>
        <th>動物的類型</th>
        <th>動物性別</th>
        <th>動物體型</th>
        <th>動物年紀</th>
        <th>圖片</th>
        <th>動物所屬收容所名稱:</th>
        <th>地址</th>
        <th>連絡電話</th>

        {% for i in jd %}  <!-- #jd為json所有資料 i則是現在建立用來遞迴的變數 -->
        <tr>
            <td>{{i.animal_place}}</td>  <!-- #Django Template 語言 使用'.' 來顯示子項目 -->
            <td>{{i.animal_kind}}</td>
            <td>{{i.animal_sex}}</td>
            <td>{{i.animal_bodytype}}</td>
            <td>{{i.animal_age}}</td>
            <td><img src="{{i.album_file}}" width="60" height="100"></td>
            <td>{{i.shelter_name}}</td>
            <td>{{i.shelter_address}}</td>
            <td>{{i.shelter_tel}}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

 

在<urls.py>添加 crawlerall 的路徑,並到瀏覽器執行:

106.JPG

3.分頁顯示多筆資料

在 <views.py> 中建立一個名為 crawlerpage 的自訂函數

學習紀錄(八) 這裡將進行分頁顯示,避免網頁資料太多爬取過久

跟之前不同的地方是,這裡是分析 json 資料來做分頁

建立一個名為 jd2 的變數,把分析好的 jd 分成10筆資料,再將 jd2 傳到前台顯示

page1 = 1
def crawlerpage(request,pageindex=None):
    global page1
    res = requests.get('http://data.coa.gov.tw/Service/OpenData/AnimalOpenData.aspx')
    ress = res.text
    jd = json.loads(ress)
    animal_place=[]

    for item in jd:
        animal_place.append(item['animal_place'])

    datasize = len(animal_place)  #資料筆數
    pagesize = 10 #每頁資料筆數
    totpage = math.ceil(datasize / pagesize)

    if pageindex == None:  #無參數
        page1 = 1
        jd2 = jd[:pagesize] #取前10筆
    elif pageindex =='1':  #上一頁
        start = (page1-2)*pagesize #該頁的第1筆資料
        if start >=0:  #有前頁資料就顯示
            jd2 = jd[start:(start+pagesize)]
            page1 -= 1
    elif pageindex == '2':  #下一頁
        start = page1*pagesize
        if start < datasize: #有下頁資料就顯示
            jd2 = jd[start:start+pagesize]
            page1 = page1 + 1
    elif pageindex == '3': #由詳細頁面返回首頁
        start = (page1-1)*pagesize  #取得原有頁面第1筆資料
        jd2 = jd[start:start+pagesize]
    currentpage = page1

    return render(request,"crawlerpage.html",locals())

創建一個名為 <crawlerpage.html> 的模版

這邊新增了顯示當前頁數的訊息

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>分頁顯示 json 所有資料</title>
</head>
<body>
    <h2>分頁顯示 json 所有資料</h2>
    <table border="3" cellpadding="2" cellspacing="2">
        <th>動物的實際所在地</th>
        <th>動物的類型</th>
        <th>動物性別</th>
        <th>動物體型</th>
        <th>動物年紀</th>
        <th>圖片</th>
        <th>動物所屬收容所名稱:</th>
        <th>地址</th>
        <th>連絡電話</th>

        {% for i in jd2 %}  <!-- #jd2為json所有資料 i則是現在建立用來遞迴的變數 -->
        <tr>
            <td>{{i.animal_place}}</td>  <!-- #Django Template 語言 使用'.' 來顯示子項目 -->
            <td>{{i.animal_kind}}</td>
            <td>{{i.animal_sex}}</td>
            <td>{{i.animal_bodytype}}</td>
            <td>{{i.animal_age}}</td>
            <td><img src="{{i.album_file}}" width="60" height="100"></td>
            <td>{{i.shelter_name}}</td>
            <td>{{i.shelter_address}}</td>
            <td>{{i.shelter_tel}}</td>
        </tr>
        {% endfor %}
    </table>

    <h3><div class="topfunction" align="center">
        {% if currentpage > 1 %}
            <a href="/crawlerpage/1/" title="上一頁">上一頁</a>
        {% endif %}
          -當前在第 {{currentpage}} 頁 -  
        {% if currentpage < totpage %}
            <a href="/crawlerpage/2/" title="下一頁">下一頁</a>
        {% endif %}
    </div></h3>
</body>
</html>

在<urls.py>添加 crawlerpage 的路徑,並到瀏覽器執行:

    path('crawlerpage/',views.crawlerpage),
    re_path('crawlerpage/(\d+)/$',views.crawlerpage), #要導入 re_path 套件

111.JPG

 

四、分析網頁資料並顯示:

這次以 蘋果日報即時新聞 為範例,先爬取資料,再藉由Django網頁顯示

108.JPG

 

 

1.分析網頁

以F12檢視網頁,接下來要找到日期、時間、分類、標題、網址 五項資料

日期 在 <h1 class="dddd">標籤

時間 在  <ul class="rtddd slvl">標籤 底下的 <time>

分類 在  <ul class="rtddd slvl">標籤 底下的 <h2>

標題 在  <ul class="rtddd slvl">標籤 底下的 <h1>

網址 在  <ul class="rtddd slvl">標籤 底下的 <a href>

 

110.JPG

在 <views.py> 中建立一個名為 newscrawler 的自訂函數

接著爬蟲程式將依照以下步驟撰寫:

  1. 導入爬蟲需要用到的套件
  2. 連接網址
  3. 擷取網頁資料
  4. 建立空串列
  5. 將元素添加入串列
  6. 使用zip()函式集合串列

 

from bs4 import BeautifulSoup
import re
import urllib

def newscrawler(request):

    url = 'https://tw.appledaily.com/new/realtime'   #選擇網址
    user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15' #偽裝使用者
    headers = {'User-Agent':user_agent}
    data_res = urllib.request.Request(url=url,headers=headers)
    data = urllib.request.urlopen(data_res)
    data = data.read().decode('utf-8')  
    sp = BeautifulSoup(data, "html.parser")


    #當日日期
    date = sp.find("h1",{"class":"dddd"})
    print(date.text)

    #每筆資料的時間
    time= []
    times = sp.find("ul",{"class":"rtddd slvl"}).findAll("time")
    for time1 in times:
        time.append(time1.text)

    #分類
    category=[]
    categorys = sp.find("ul",{"class":"rtddd slvl"}).findAll("h2")
    for category1 in categorys:
        category.append(category1.text)

    #標題
    title=[]
    titles = sp.find("ul",{"class":"rtddd slvl"}).findAll("h1")
    for title1 in titles:
        title.append(title1.text)
    
    #網址
    link=[]
    links = sp.find("ul",{"class":"rtddd slvl"}).findAll("a",href = re.compile('appledaily'))
    for link1 in links:
        link.append(link1['href'])
    all = zip(time,category,title,link)
    return render(request,"newscrawler.html",locals())

 

創建一個名為 <newscrawler.html> 的模版

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>蘋果日報 即時新聞</title>
</head>
<body>
    <h2>顯示 蘋果日報 即時新聞 {{date}}</h2>
    <table border="3" cellpadding="2" cellspacing="2">
        <th>時間</th>
        <th>分類</th>
        <th>標題</th>
        <th>網址</th>


        {% for time,category,title,link in all %} <!-- 使用zip將串列集合後即可同時調用 -->
        <tr>
            <td>{{time}}</td>
            <td>{{category}}</td>
            <td><a  Target="_blank" href="{{link}}">{{title}}</td>  <!-- 以新視窗開啟連結 -->
            <td>{{link}}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

 

在<urls.py>添加 newscrawler 的路徑,並到瀏覽器執行:

109.JPG

3.分頁顯示多筆資料

在 <views.py> 中建立一個名為 newspage 的自訂函數

學習紀錄(八) 這裡將進行分頁顯示,避免網頁資料太多爬取過久

跟之前不同的地方是,這裡是要將網路爬蟲的多個 List 加入一個 zip

再把zip 放入一個名為 listall 的 list ,

而裡面的元素則改為 時間:listall[0] 、分類:listall[1] 、標題:listall[2] 、網址:listall[3]、

建立一個名為listall2 的變數,把分析好的 listall 分成6筆資料,再將 listall2 傳到前台顯示

page2 = 1
def newspage(request,pageindex2=None):  #蘋果日報即時新聞爬蟲

    url = 'https://tw.appledaily.com/new/realtime'   #選擇網址
    user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15' #偽裝使用者
    headers = {'User-Agent':user_agent}
    data_res = urllib.request.Request(url=url,headers=headers)
    data = urllib.request.urlopen(data_res)
    data = data.read().decode('utf-8')  
    sp = BeautifulSoup(data, "html.parser")
    #當日日期
    dated = sp.find("h1",{"class":"dddd"})
    date = dated.text
    #每筆資料的時間
    time= []
    times = sp.find("ul",{"class":"rtddd slvl"}).findAll("time")
    for time1 in times:
        time.append(time1.text)
    #分類
    category=[]
    categorys = sp.find("ul",{"class":"rtddd slvl"}).findAll("h2")
    for category1 in categorys:
        category.append(category1.text)
    #標題
    title=[]
    titles = sp.find("ul",{"class":"rtddd slvl"}).findAll("h1")
    for title1 in titles:
        title.append(title1.text)
    #網址
    link=[]
    links = sp.find("ul",{"class":"rtddd slvl"}).findAll("a",href = re.compile('appledaily'))
    for link1 in links:
        link.append(link1['href'])
    all = zip(time,category,title,link)
    listall = list(all)

    global page2
    datasize = len(time)
    pagesize = 6
    totpage = math.ceil(datasize / pagesize)

    if pageindex2 == None:  #無參數
        page2 = 1
        listall2 = listall[:pagesize] #取前6筆
    elif pageindex2 =='1':  #上一頁
        start = (page2-2)*pagesize #該頁的第1筆資料
        if start >=0:  #有前頁資料就顯示
            listall2 = listall[start:(start+pagesize)]
            page2 -= 1
    elif pageindex2 == '2':  #下一頁
        start = page2*pagesize
        if start < datasize: #有下頁資料就顯示
            listall2 = listall[start:start+pagesize]
            page2 = page2 + 1
    elif pageindex2 == '3': #由詳細頁面返回首頁
        start = (page2-1)*pagesize  #取得原有頁面第1筆資料
        listall2 = listall[start:start+pagesize]
    currentpage = page2

    return render(request,"newspage.html",locals())

 

創建一個名為 <newspage.html> 的模版

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>分頁顯示 蘋果日報 即時新聞</title>
</head>
<body>
    <h2>分頁顯示 蘋果日報 即時新聞 {{date}}</h2>
    <table border="3" cellpadding="2" cellspacing="2">
        <th>時間</th>
        <th>分類</th>
        <th>標題</th>
        <th>網址</th>


        {% for i in listall2 %} 
        <tr>
            <td>{{i.0}}</td>
            <td>{{i.1}}</td>
            <td><a  Target="_blank" href="{{i.3}}">{{i.2}}</td>  <!-- 以新視窗開啟連結 -->
            <td>{{i.3}}</td>
        </tr>
        {% endfor %}
    </table>
    <h3><div class="topfunction" align="center">
        {% if currentpage > 1 %}
            <a href="/newspage/1/" title="上一頁">上一頁</a>
        {% endif %}
          -當前在第 {{currentpage}} 頁 -  
        {% if currentpage < totpage %}
            <a href="/newspage/2/" title="下一頁">下一頁</a>
        {% endif %}
    </div></h3>
</body>
</html>

在<urls.py>添加 newspage 的路徑,並到瀏覽器執行:

    path('newspage/',views.newspage),
    re_path('newspage/(\d+)/$',views.newspage),

 

112.JPG

arrow
arrow
    全站熱搜

    ivankao 發表在 痞客邦 留言(1) 人氣()