Tabelle mit PYH aus Liste generieren

Django, Flask, Bottle, WSGI, CGI…
Antworten
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

Hallo,

ich möchte eine Website mit PYH generieren. Diese solle bestimmte Artikel aus RSS-Feeds enthalten. Leider weiß ich nicht so genau, wie die die Tabelle erstellen kann, bzw. es geht nicht so wie ich es mir denke.

Zu nächst erstelle ich eine Liste in der jede Zeile sechs Einträge enthält. Aus dieser Liste soll die Tabelle erstellt werden. Das Beispiel von de PYH-Webseite funktioniert nicht ohne weiteres für Listen.

Hier der Code:

Code: Alles auswählen


import feedparser
import re, os, sys, pyh
from pyh import *


listFeed = []
listResult = []
listSubofinterest = ["Obama", "Merkel","Assad"]

listFeed.append(['http://www.spiegel.de/schlagzeilen/index.rss',1])
listFeed.append(['www.welt.de/?config=feeds_startseite', 2])

page = PyH('My News')
page.addJS('http://code.jquery.com/jquery-1.9.1.js')

for feed in listFeed:
    
    entries = feedparser.parse(feed[0])

    es = entries['feed']
    for entry1 in es:
        if entry1 == 'subtitle':
            print "1a",es
        
            for entry in entries.entries:
        
                for subject in listSubofinterest:
                    
                    if entry['title'].find(subject) != -1:
                            
                        listResult.append([feed[1],entries['feed']['title'],subject, entry.title, entry.description, entry.link])

rows = len(listResult)
cols = len(listResult[0])

print "list dim",rows, cols


mytab = page << table()

for result in listResult:
    
    mytr = mytab << tr()
    print "result", result
    for r in result:
        
        print "r",r
        tr << td(r)
        

page << script("$(':header').css({ background:'red', color:'black' });")
page.printOut("test.html")


Aktuell gibt es eine Fehlermeldung:

Code: Alles auswählen

TypeError: unsupported operand type(s) for <<: 'type' and 'td'
Hat jemand einen Tip?


Danke
Peter
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

Selber gefunden:

Code: Alles auswählen

mytr << td(r)
BlackJack

@djangofish: Ein paar Anmerkungen zum Quelltext:

Von den importierten Modulen wird mehr als die Hälfte überhaupt gar nicht verwendet. Der Sternchen-Import ist unschön.

Der konkrete Datentyp hat in Namen nichts zu suchen. Dann kann man den Typ des Wertes nicht mehr ändern ohne dass man den Namen ändern muss oder irreführende Namen im Quelltext hat. Das läuft auch dem „duck typing” zuwider.

Abkürzungen und komische Wortschöpfungen wie `listSubofinterest` sind keine gute Idee weil sie beim Leser mehr Fragen aufwerfen als beantworten.

Code auf Modulebene der keine Konstanten definiert wird spätestens dann unsauber wenn man anfängt den Code auf Funktionen zu verteilen.

`listFeed` wird etwas umständlich gefüllt. Es gibt Listenliterale, man braucht nicht für jedes Element einen Methodenaufruf. Das verleiht dem Quelltext zusätzlich zu der ``<<``-Operatorüberladung irgendwie einen C++-touch.

Auslesen der Feeds und erstellen der HTML-Seite ist ja *fast* getrennt in dem Skript, nur das `page` viel zu früh erstellt wird. Man sollte Namen in der Nähe des Codes definieren wo sie dann auch verwendet werden und nicht Quelltext für einen Arbeitsschritt der etwas ganz anderes tut dazwischen platzieren.

Aus dem Quelltext wird, zumindest mir, nicht wirklich klar was das zweite Element in denn Listen bedeuten soll welche Feeds beschreiben. Weil ``feed[1]`` halt nicht wirklich etwas über die Bedeutung verrät. Statt nichtssagender Indexwerte hätte man hier in der Schleife schon die beiden Elemente an jeweils einen aussagekräftigen Namen binden können.

In der Feed-Auswertung sind die Namen `entries`, `es`, `entry1` und `entry` sehr verwirrend. Ich bin mir auch fast sicher das tut nicht das was es soll. Sollte es doch, so erscheint der Code ziemlich verworren und unsinnig. Das mit dem Test auf 'subtitle' in der Schleife macht keinen Sinn. Ebenso ist das Prüfen auf die interessanten Worte im Titel fehlerhaft, weil für *jeden* Treffer ein Ergebniseintrag erstellt wird. Wenn also die Schlagzeile „Obame trifft Merkel” lautet, wird der gleiche Feed-Eintrag *zweimal* hintereinander dem Ergebnis hinzugefügt. Das erscheint mir nicht besonders sinnvoll. Der Test mit ``find(…) != -1`` ist umständlich ausgedrück — dafür gibt es den ``in``-Operator.

Beim Erstellen der HTML-Seite sind die Namen wieder fast durchweg unzureichend. Beispielsweise `mytab` — `my` sagt im Grunde nichts aus und ist nur ein unnötiges Füllwort und `tab` hat eine Bedeutung, nämlich Karteikartenreiter, was ein übliches UI-Element in HTML ist, und damit ist der Name irreführend wenn er für eine Tabelle steht.

Das ganze könnte dann so aussehen:

Code: Alles auswählen

#!/usr/bin/env python
import feedparser
import pyh


def main():
    feeds = [
        ['http://www.spiegel.de/schlagzeilen/index.rss', 1],
        ['http://www.welt.de/?config=feeds_startseite', 2]
    ]
    results = []
    subject_keywords = ['e', 'o', 'Obama', 'Merkel', 'Assad']

    for feed_url, some_magic_number in feeds:
        feed = feedparser.parse(feed_url)
        feed_title = feed['feed']['title']
        for entry in feed.entries:
            #
            # TODO Really create one result entry for each matching subject?
            #
            for subject in subject_keywords:
                if subject in entry['title']:
                    print entry.keys()
                    results.append(
                        [
                            str(some_magic_number),
                            feed_title,
                            subject,
                            entry.title,
                            entry.get('description', ''),
                            entry.link
                        ]
                    )

    page = pyh.PyH('My News')
    feed_table = page << pyh.table()
    for row in results:
        table_row = feed_table << pyh.tr()
        for cell_content in row:
            table_row << pyh.td(cell_content.encode('utf-8'))

    page.addJS('http://code.jquery.com/jquery-1.9.1.js')
    page << pyh.script("$(':header').css({ background:'red', color:'black' });")

    page.printOut('test.html')


if __name__ == '__main__':
    main()
Wie bist Du eigentlich auf PyH gekommen? Die Namen und das überladen von ``<<`` sieht mehr nach C++ als nach Python aus. Das ist Version 0.0.1 von vor drei Jahren und seitdem hat sich da auch nichts mehr getan. Man kann mit verbreiteren Modulen/Packages wie `BeautifulSoup` oder `lxml.html` auch programmatisch HTML erzeugen. Wobei ich das letztendlich eher nicht machen würde, sondern eine Template-Engine wie beispielsweise Jinja2 verwenden würde. Damit kann man einfacher die Ausgabe gestalten als mit Code in einer Programmiersprache.
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

Hallo,

ich habe mir jinja2 schon mal kurz angesehen,...aber ich es mir etwas zuviel "Ballast" um eine einzelne Website zu erstellen. Es hatte den Anschein, als wäre es ein Framework wie Django.

Danke für deine Überarbeitung, bei

Code: Alles auswählen

feed_title = feed['feed']['title']
gibt er mir einen Fehler, aber das war nicht so schlimm. Ansonsten hat es funktioniert!:)

Danke nochmals
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

djangofish hat geschrieben: ich habe mir jinja2 schon mal kurz angesehen,...aber ich es mir etwas zuviel "Ballast" um eine einzelne Website zu erstellen. Es hatte den Anschein, als wäre es ein Framework wie Django.
Öh... dann auf auf und schau es Dir *noch einmal* etwas länger / genauer an! Jinja2 ist eine *Template*-Engine, kein Web-Framework! Und was Ballast anbelangt: Jinja2 hat eine ziemlich angenehme API - da merkst Du kaum, das Du da ein sehr mächtiges Werkzeug für die HTML-Generierung hast.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Mal das Beispiel mit einem Jinja2-Template:

Code: Alles auswählen

#!/usr/bin/env python
import io
import feedparser
from jinja2 import Environment, FileSystemLoader


def main():
    feeds = [
        ['http://www.spiegel.de/schlagzeilen/index.rss', 1],
        ['http://www.welt.de/?config=feeds_startseite', 2]
    ]
    results = []
    subject_keywords = ['e', 'o', 'Obama', 'Merkel', 'Assad']

    for feed_url, some_magic_number in feeds:
        feed = feedparser.parse(feed_url)
        feed_title = feed['feed']['title']
        for entry in feed.entries:
            #
            # TODO Really create one result entry for each matching subject?
            #
            for subject in subject_keywords:
                if subject in entry['title']:
                    results.append(
                        [
                            str(some_magic_number),
                            feed_title,
                            subject,
                            entry.title,
                            entry.get('description', ''),
                            entry.link
                        ]
                    )

    environment = Environment(loader=FileSystemLoader('.'))
    template = environment.get_template('test.tpl')
    with io.open('test.html', 'w', encoding='utf-8') as result_file:
        result_file.writelines(template.render(result=results))
    

if __name__ == '__main__':
    main()
Und das Template ``test.tpl``:

Code: Alles auswählen

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>My News</title>
</head>
<body>
  <table>
    <tbody>
      {% for row in result %}
        <tr>
          {% for cell_content in row %}
            <td>{{cell_content}}</td>
          {% endfor %}
        </tr>
      {% endfor %}
    </tbody>
  </table>
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
  <script> $(":header").css({ background: "red", color: "black" }); </script>
</body>
</html>
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

Hallo,

danke erstmal für deine weitere Hilfe. Im Prinzip hab ich es so ähnlich selber mit web.py zusammengeschustert
Ich wollte die Tabelle mit jquery und dataTables etwas erweitern. Leider scheint es wichtig zu sein wann Javascript geladen wird. Jedenfalls habe ich es so wie es nachfolgend steht nicht zum laufen bekommen. Eine statische Tabelle hingegen geht wunderbar.

Code: Alles auswählen


import os
import web
import feedparser
from jinja2 import Environment,FileSystemLoader

urls = ("/.*", "hello")
app = web.application(urls, globals())

def render_template(template_name, **context):
    extensions = context.pop('extensions', [])
    globals = context.pop('globals', {})

    jinja_env = Environment(
            loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')),
            extensions=extensions,
            )
    jinja_env.globals.update(globals)

    #jinja_env.update_template_context(context)
    return jinja_env.get_template(template_name).render(context)

class hello:
    def GET(self):
        output = getFeedContent()
        return render_template('hello.html', output=output)
def getFeedContent():
    
    feeds = [
        ['http://www.spiegel.de/schlagzeilen/index.rss', 1],
        ['http://www.welt.de/?config=feeds_startseite', 2]
    ]
    results = []
    subject_keywords = ['e', 'o', 'Obama', 'Merkel', 'Assad']

    for feed_url, some_magic_number in feeds:
        feed = feedparser.parse(feed_url)
        
        for entry in feed.entries:
            
            # 
            # TODO Really create one result entry for each matching subject?
            # 
            for subject in subject_keywords:
                #print entry['title'].find(subject)
                if entry['title'].find(subject) != -1:
                    #print "sub",subject
                    results.append(
                        [
                            some_magic_number,
                            feed['feed']['title'],
                            subject,
                            entry.title,
                            entry.description,
                            "<a href="+entry.link+" target='_blank'>link</a>",
                            #entry.pubDate
                        ]
                    )
    print "s"
    return results

if __name__ == "__main__":
    app.run()


Dazu dieses Template:

Code: Alles auswählen


<style type="text/css" title="currentStyle">
    @import "/demo_table.css";
    @import "/demo_page.css";
</style>
<script type="text/javascript" charset="utf-8" src="/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="/jquery.dataTables.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready( function () {
	$('#tablefeeds').dataTable();
} );
</script>



<table id="tablefeeds" class="display">

    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
            <th>Column 4</th>
            <th>Column 5</th>
            <th>Column 6</th>
        </tr>
    </thead>

	<tbody>
	{%- for o in output %}
	  <tr>
	  {%- for column in o %}
	    <td>{{ column }}</td>
	  {%- endfor %}
	  </tr>
	{%- endfor %}
	</tbody>
</table>



Habt ihr da noch nen Tip?

Vielen Dank
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja, kein Web.py verwenden wäre ein guter Schritt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

und was dann?
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

djangofish hat geschrieben:und was dann?
Wenn es eher leichtgewichtig sein sollte, dann beispielsweise bottle oder Flask.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@djangofish: wobei man bei Deinem Problem sagen muß, dass es höchstwahrscheinlich nicht am benutzten Framework liegt. Du solltest im Browser Deiner Wahl die Entwicklertools aufrufen und prüfen, ob alle Scripte fehlerfrei geladen werden und ob es sonstige Fehlermeldungen gibt.
djangofish
User
Beiträge: 51
Registriert: Dienstag 16. Oktober 2012, 09:43
Kontaktdaten:

Danke für eure Antworten. Habs jetzt doch mit Django gebastelt und es läuft ne Woche schon ganz gut. :)
Antworten