<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Python】100行Python代碼輕松開發(fā)個(gè)人博客

          共 17260字,需瀏覽 35分鐘

           ·

          2021-05-05 12:16


          ?

          本文示例代碼已上傳至我的Github倉庫https://github.com/CNFeffery/DataScienceStudyNotes

          ?

          1 簡(jiǎn)介

          這是我的系列教程「Python+Dash快速web應(yīng)用開發(fā)」的第十六期,在過往所有的教程及案例中,我們所搭建的Dash應(yīng)用的訪問地址都是單一的,是個(gè)「單頁面」應(yīng)用,即我們所有的功能都排布在同一個(gè)url之下。

          而隨著我們所編寫的Dash應(yīng)用功能的日趨健全和復(fù)雜,單一url的內(nèi)容組織方式無法再很好的滿足需求,也不利于構(gòu)建邏輯清晰的web應(yīng)用。

          因此我們需要在Dash應(yīng)用中引入「路由」的相關(guān)功能,即在當(dāng)前應(yīng)用主域名下,根據(jù)不同的url來渲染出具有不同內(nèi)容的頁面,就像我們?nèi)粘J褂玫慕^大多數(shù)網(wǎng)站那樣。

          而今天的教程,我們就將一起學(xué)習(xí)在Dash中編寫多url應(yīng)用并進(jìn)行路由控制的常用方法。

          圖1

          2 編寫多頁面Dash應(yīng)用

          2.1 Location()的基礎(chǔ)使用

          要想在Dash中實(shí)現(xiàn)url路由功能,首先我們需要捕獲到瀏覽器中地址欄對(duì)應(yīng)的url是什么,這在Dash中可以通過在app.layout中構(gòu)建一個(gè)可以持續(xù)監(jiān)聽當(dāng)前Dash應(yīng)用url信息的部件來實(shí)現(xiàn)。

          我們使用官方依賴庫dash_core_components中的Location()部件來實(shí)現(xiàn)上述功能,它的核心參數(shù)或?qū)傩杂?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;overflow-wrap: break-word;border-radius: 4px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">href、pathnamesearchhash,讓我們通過下面的例子來直觀的了解它們各自記錄了地址欄url中的哪些信息:

          ?

          app1.py

          ?
          import dash
          import dash_core_components as dcc
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          from dash.dependencies import Input, Output

          app = dash.Dash(__name__)

          app.layout = dbc.Container(
              [
                  dcc.Location(id='url'),
                  html.Ul(id='output-url')
              ],
              style={
                  'paddingTop''100px'
              }
          )


          @app.callback(
              Output('output-url''children'),
              [Input('url''href'),
               Input('url''pathname'),
               Input('url''search'),
               Input('url''hash')]
          )
          def show_location(href, pathname, search, hash):
              return (
                  html.Li(f'當(dāng)前href為:{href}'),
                  html.Li(f'當(dāng)前pathname為:{pathname}'),
                  html.Li(f'當(dāng)前search為:{search}'),
                  html.Li(f'當(dāng)前hash為:{hash}'),
              )


          if __name__ == '__main__':
              app.run_server(debug=True)

          圖2

          因此在Dash中編寫多url應(yīng)用的核心策略是利用埋點(diǎn)Location()捕獲到地址欄對(duì)應(yīng)信息的變化,并以這些信息作為回調(diào)函數(shù)的輸入,來輸出相應(yīng)的頁面內(nèi)容變化,讓我們從下面這個(gè)簡(jiǎn)單的例子中g(shù)et上述這一套流程的運(yùn)作方式:

          ?

          app2.py

          ?
          import dash
          import dash_core_components as dcc
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          from dash.dependencies import Input, Output

          app = dash.Dash(__name__)

          app.layout = dbc.Container(
              [
                  dcc.Location(id='url', refresh=False),
                  dbc.Row(
                      [
                          dbc.Col(
                              [
                                  html.A('頁面A', href='/pageA'),
                                  html.Br(),
                                  html.A('頁面B', href='/pageB'),
                                  html.Br(),
                                  html.A('頁面C', href='/pageC'),
                              ],
                              width=2,
                              style={
                                  'backgroundColor''#eeeeee'
                              }
                          ),
                          dbc.Col(
                              html.H3(id='render-page-content'),
                              width=10
                          )
                      ]
                  )
              ],
              style={
                  'paddingTop''20px',
                  'height''100vh',
                  'weight''100vw'
              }
          )


          @app.callback(
              Output('render-page-content''children'),
              Input('url''pathname')
          )
          def render_page_content(pathname):
              if pathname == '/':
                  return '歡迎來到首頁'

              elif pathname == '/pageA':
                  return '歡迎來到頁面A'

              elif pathname == '/pageB':
                  return '歡迎來到頁面B'

              elif pathname == '/pageC':
                  return '歡迎來到頁面C'

              else:
                  return '當(dāng)前頁面不存在!'


          if __name__ == '__main__':
              app.run_server(debug=True)

          圖3

          2.2 利用Location()實(shí)現(xiàn)頁面重定向

          在上一小節(jié)我們對(duì)dcc.Location()的基礎(chǔ)用法進(jìn)行了介紹,而它的功能可不止監(jiān)聽url變化這么簡(jiǎn)單,我們還可以利用它在Dash中實(shí)現(xiàn)「重定向」,使用方式簡(jiǎn)單一句話描述就是將Location()作為對(duì)應(yīng)回調(diào)的輸出(記住一定要定義id屬性),這樣地址欄url會(huì)在回調(diào)完成后對(duì)應(yīng)跳轉(zhuǎn)。

          讓我們通過下面這個(gè)簡(jiǎn)單的例子來get這個(gè)技巧:

          ?

          app3.py

          ?
          import dash
          import dash_core_components as dcc
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          from dash.dependencies import Input, Output

          app = dash.Dash(__name__)

          app.layout = dbc.Container(
              [
                  html.Div(id='redirect-url-container'),

                  dbc.Button('跳轉(zhuǎn)到頁面A', id='jump-to-pageA', style={'marginRight''10px'}),

                  dbc.Button('跳轉(zhuǎn)到頁面B', id='jump-to-pageB'),
              ],
              style={
                  'paddingTop''100px'
              }
          )


          @app.callback(
              Output('redirect-url-container''children'),
              [Input('jump-to-pageA''n_clicks'),
               Input('jump-to-pageB''n_clicks')],
          )
          def jump_to_target(a_n_clicks, b_n_clicks):
              ctx = dash.callback_context

              if ctx.triggered[0]['prop_id'] == 'jump-to-pageA.n_clicks':
                  return dcc.Location(id='redirect-url', href='/pageA')

              elif ctx.triggered[0]['prop_id'] == 'jump-to-pageB.n_clicks':
                  return dcc.Location(id='redirect-url', href='/pageB')

              return dash.no_update


          if __name__ == '__main__':
              app.run_server(debug=True)

          圖4

          2.3 用Link()實(shí)現(xiàn)“無縫”頁面切換

          你應(yīng)該注意到了,在Dash中利用Location()和普通的A()部件實(shí)現(xiàn)跳轉(zhuǎn)時(shí),頁面在跳轉(zhuǎn)后會(huì)整體刷新,這會(huì)一定程度上破壞整個(gè)web應(yīng)用的整體體驗(yàn)。

          dash_core_components中的Link()部件則是很好的替代,它的基礎(chǔ)屬性與A()無異,但額外的refresh參數(shù)默認(rèn)為False,會(huì)在點(diǎn)擊后進(jìn)行Dash應(yīng)用內(nèi)跳轉(zhuǎn)時(shí)無縫切換,頁面不會(huì)整體刷新:

          ?

          app4.py

          ?
          import dash
          import dash_core_components as dcc
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          from dash.dependencies import Input, Output

          app = dash.Dash(__name__)

          app.layout = dbc.Container(
              [
                  dcc.Location(id='url'),

                  dcc.Link('頁面A', href='/pageA', refresh=True),
                  html.Br(),
                  dcc.Link('頁面B', href='/pageB'),

                  html.Hr(),

                  html.H1(id='render-page-content')
              ],
              style={
                  'paddingTop''100px'
              }
          )


          @app.callback(
              Output('render-page-content''children'),
              Input('url''pathname')
          )
          def render_page_content(pathname):
              if pathname == '/':
                  return '歡迎來到首頁'

              elif pathname == '/pageA':
                  return '歡迎來到頁面A'

              elif pathname == '/pageB':
                  return '歡迎來到頁面B'

              elif pathname == '/pageC':
                  return '歡迎來到頁面C'

              else:
                  return '當(dāng)前頁面不存在!'


          if __name__ == '__main__':
              app.run_server(debug=True)

          圖5

          類似的功能還有dash_bootstrap_components中的NavLink(),用法與Link()相似,這里就不再贅述。

          3 動(dòng)手開發(fā)個(gè)人博客網(wǎng)站

          掌握了今天的知識(shí)之后,我們來用Dash開發(fā)一個(gè)簡(jiǎn)單的個(gè)人博客網(wǎng)站,思路是在Location()監(jiān)聽url變化的前提下,后臺(tái)利用網(wǎng)絡(luò)爬蟲從我的博客園Dash主題下爬取相應(yīng)的網(wǎng)頁內(nèi)容,并根據(jù)用戶訪問來渲染出對(duì)應(yīng)的文章:

          ?

          app5.py

          ?
          import dash
          import dash_core_components as dcc
          import dash_html_components as html
          import dash_bootstrap_components as dbc
          import dash_dangerously_set_inner_html  # 用于直接渲染html源碼字符串
          from dash.dependencies import Input, Output

          import re
          from html import unescape
          import requests
          from lxml import etree

          app = dash.Dash(__name__, suppress_callback_exceptions=True)

          app.layout = html.Div(
              dbc.Spinner(
                  dbc.Container(
                      [
                          dcc.Location(id='url'),

                          html.Div(
                              id='page-content'
                          )
                      ],
                      style={
                          'paddingTop''30px',
                          'paddingBottom''50px',
                          'borderRadius''10px',
                          'boxShadow''rgb(0 0 0 / 20%) 0px 13px 30px, rgb(255 255 255 / 80%) 0px -13px 30px'
                      }
                  ),
                  fullscreen=True
              )
          )


          @app.callback(
              Output('article-links''children'),
              Input('url''pathname')
          )
          def render_article_links(pathname):
              response = requests.get('https://www.cnblogs.com/feffery/tag/Dash/',
                                      headers={
                                          'User-Agent''Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'
                                      })

              tree = etree.HTML(response.text)

              posts = [
                  (href, title.strip())
                  for href, title in zip(
                      tree.xpath("http://div[@class='postTitl2']/a/@href"),
                      tree.xpath("http://div[@class='postTitl2']/a/span/text()")
                  )
              ]

              return [
                  html.Li(
                      dcc.Link(title, href=f'/article-{href.split("/")[-1]}', target='_blank')
                  )
                  for href, title in posts
              ]


          @app.callback(
              Output('page-content''children'),
              Input('url''pathname')
          )
          def render_article_content(pathname):
              if pathname == '/':

                  return [
                      html.H2('博客列表:'),

                      html.Div(
                          id='article-links',
                          style={
                              'width''100%'
                          }
                      )
                  ]

              elif pathname.startswith('/article-'):

                  response = requests.get('https://www.cnblogs.com/feffery/p/%s.html' % re.findall('\d+', pathname)[0])

                  tree = etree.HTML(response.text)

                  return (
                      html.H3(tree.xpath("http://title/text()")[0].split(' - ')[0]),
                      html.Em('作者:費(fèi)弗里'),
                      dash_dangerously_set_inner_html.DangerouslySetInnerHTML(
                          unescape(etree.tostring(tree.xpath('//div[@id="cnblogs_post_body"]')[0]).decode())
                      )
                  )

              return dash.no_update


          if __name__ == '__main__':
              app.run_server(debug=True)

          圖6

          按照類似的思路,你可以隨心所欲地開發(fā)自己的多頁面應(yīng)用,進(jìn)一步豐富完善你的Dash應(yīng)用功能。


          以上就是本文的全部?jī)?nèi)容,歡迎在評(píng)論區(qū)發(fā)表你的意見和想法。


          往期精彩回顧





          本站qq群851320808,加入微信群請(qǐng)掃碼:

          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  最新无码在线观看 | 加勒比久操视频 | 天干天干天夜夜爽 | 五月婷婷看看色色 | 国产黄色视频大全 |