0

thanks for everything so far! just one more issue then time to polish off.

I cant seem to find a way to output text to a label, also if possible i want to be able to display a link in that label so the user can open a web page.

I have tried defining new procedures to do it but while the text is designated at build i cant seem to change it at all after that! I keep getting variables not defined as im obviously doing it in the wrong places!

import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.spinner import Spinner
from bs4 import BeautifulSoup
from urllib import request
import sys, traceback
from functools import partial
import re
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.image import Image


class DSFRSapp(App):
    def build(self):
        self.root = FloatLayout()
        i = Image(source='DSFRSLogo.png',
                  allow_stretch=True,
                  pos_hint = ({'center_x':0.5, 'y': .25}))
        spinner = Spinner(text='Select a Station',
                             values=('Appledore','Axminster','Bampton','Barnstaple','Bere Alston','Bideford','Bovey Tracey','Braunton','Bridgwater','Brixham','Buckfastleigh','Budleigh Salterton','Burnham on sea','Camels Head','Castle Cary','Chagford','Chard','Cheddar','Chulmleigh','Colyton','Combe Martin','Crediton','Crewkerne','Crownhill','Cullompton','Dartmouth','Dawlish','Exeter Danes Castle','Exeter Middlemoor','Exmouth','Frome','Glastonbury','Greenbank','Hartland','Hatherleigh','Holsworthy','Honiton','Ilfracombe','Ilminster','Ivybridge','Kingsbridge','Kingston','Lundy Island','Lynton','Martock','Minehead','Modbury','Moretonhampstead','Nether Stowey','Newton Abbot','North Tawton','Okehampton','Ottery St Mary','Paignton','Plympton','Plymstock','Porlock','Princetown','Salcombe','Seaton','Shepton Mallet','Sidmouth','Somerton','South Molton','Street','Taunton','Tavistock','Teignmouth','Tiverton','Topsham','Torquay','Torrington','Totnes','USAR','Wellington','Wells','Williton','Wincanton','Witheridge','Wiveliscombe','Woolacombe','Yelverton','Yeovil'),
                            size_hint=(None, None),
                            size=(150, 44),
                            pos_hint = ({'center_x':0.5, 'y': 0.35}))
        L = Label(text="Results will display here",
                      size_hint=(None, None),
                      pos_hint =({'center_x':0.5, 'y': 0.25}),
                      size=(150, 44))
        self.root.add_widget(spinner)
        self.root.add_widget(L)
        self.root.add_widget(i)
        spinner.bind(text=show_selected_value)



def show_selected_value(spinner, text):
    FindIncident(text)


def FindIncident( sStation, *args ):
    webpage = request.urlopen("http://www.dsfire.gov.uk/News/Newsdesk/IncidentsPast7days.cfm?siteCategoryId=3&T1ID=26&T2ID=35")#main page
    soup = BeautifulSoup(webpage)
    incidents = soup.find(id="CollapsiblePanel1") #gets todays incidents panel
    Links = [] #create list call Links

    for line in incidents.find_all('a'): #get all hyperlinks
        Links.append("http://www.dsfire.gov.uk/News/Newsdesk/"+line.get('href')) #loads links into Links list while making them full links
    n = 0
    e = len(Links)
    if e == n: #if no links available no need to continue
    #output message to label
       print("nothing found please try again later")
       sys.exit(0)
    sFound = False
    while n < e: #loop through links to find station
        if sFound: #if the station has been found stop looking
             sys.exit(0)
        webpage = request.urlopen(Links[n]) #opens link in list)
        soup = BeautifulSoup(webpage) #loads webpage
        if soup.find_all('p', text=re.compile(r'{}'.format(sStation))) == []:#check if returned value is found
        #do nothing leaving blank gave error
            a = "1" #this is pointless but stops the error
        else:
            print(soup.find_all('p', text=re.compile(r'{}'.format(sStation))))
            WebLink = Links[n]
            sFound = True # to avoid un needed goes through the loop process
        n=n+1 # moves counter to next in list
    if not sFound: #after looping process if nothing has been found output nothing found
        print("nothing found please try again later ")
    #output to label
    return;



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

I should mention that I have a logo that gets displayed i will position the widgets better for when the screen re sizes I want the background colour to be white maybe with a thin red border (just to jazz it up)

if you have the answer to any of these questions great! but the priority at the moment is outputing the result of the web search to the label instead of printing to the console preferably with the link (WebLink)

Thanks again, once i get these issues hammered out I'm planning on giving it to my fire service as a way for fire fighters significant others to have an idea on when the firefighters are likely to finish a shout. but only once i can package it to android and maybe get someone else to port it to ios as i dont have a mac.

Raif Jackson
  • 59
  • 2
  • 11

1 Answers1

0

I've altered the code to be more pythonic (especially looping). The label is now connected but I haven't tried to debug your web scraping. You'll have to recheck it yourself.

import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.spinner import Spinner
from bs4 import BeautifulSoup
from urllib import request
import sys, traceback
from functools import partial
import re
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.image import Image
from kivy.properties import ObjectProperty

kv = '''
<IncidentScreen>:
    station: stationSpinner
    results: resultsLabel
    Image:
        source:'DSFRSLogo.png'
        allow_stretch:True
        pos_hint: {'center_x':0.5, 'y': .25}

    Spinner:
        id: stationSpinner
        text:'Select a Station'
        values: ('Appledore','Axminster','Bampton','Barnstaple','Bere Alston','Bideford','Bovey Tracey','Braunton','Bridgwater','Brixham','Buckfastleigh','Budleigh Salterton','Burnham on sea','Camels Head','Castle Cary','Chagford','Chard','Cheddar','Chulmleigh','Colyton','Combe Martin','Crediton','Crewkerne','Crownhill','Cullompton','Dartmouth','Dawlish','Exeter Danes Castle','Exeter Middlemoor','Exmouth','Frome','Glastonbury','Greenbank','Hartland','Hatherleigh','Holsworthy','Honiton','Ilfracombe','Ilminster','Ivybridge','Kingsbridge','Kingston','Lundy Island','Lynton','Martock','Minehead','Modbury','Moretonhampstead','Nether Stowey','Newton Abbot','North Tawton','Okehampton','Ottery St Mary','Paignton','Plympton','Plymstock','Porlock','Princetown','Salcombe','Seaton','Shepton Mallet','Sidmouth','Somerton','South Molton','Street','Taunton','Tavistock','Teignmouth','Tiverton','Topsham','Torquay','Torrington','Totnes','USAR','Wellington','Wells','Williton','Wincanton','Witheridge','Wiveliscombe','Woolacombe','Yelverton','Yeovil')
        size_hint: None, None
        size: (150, 44)
        pos_hint: {'center_x':0.5, 'y': 0.35}
        on_text: app.show_selected_value()

    Label:
        id: resultsLabel
        text:"Results will display here"
        color: [0,0,0,1]
        size_hint:(None, None)
        pos_hint:{'center_x':0.5, 'y': 0.25}
        size: (150, 44)

'''
class IncidentScreen(FloatLayout):
    station = ObjectProperty(None)
    results = ObjectProperty(None)

class DSFRSapp(App):

    def build(self):
        Builder.load_string(kv)
        fl = IncidentScreen()
        return fl

    def show_selected_value(self):
        incident = self.FindIncident(self.root.station.text)
        if incident:
            self.root.results.text = incident
        else:
            self.root.results.text = 'Try again later'

    def FindIncident(self, sStation, *args ):
        webpage = request.urlopen("http://www.dsfire.gov.uk/News/Newsdesk/IncidentsPast7days.cfm?siteCategoryId=3&T1ID=26&T2ID=35")#main page
        soup = BeautifulSoup(webpage)
        incidents = soup.find(id="CollapsiblePanel1") #gets todays incidents panel
        #create list call Links

        #get all hyperlinks: loads links into Links list while making them full links
        Links = [''.join(["http://www.dsfire.gov.uk/News/Newsdesk/",line.get('href')]) for line in incidents.find_all('a')]

        #loop through links to find station
        incident = ''
        for link in Links:
            print('Trying {}'.format(link))
            webpage = request.urlopen(link) #opens link in list)
            soup = BeautifulSoup(webpage) #loads webpage

            #check if returned value is found
            incident = soup.find_all('p', text=re.compile(r'{}'.format(sStation)))
            print(incident)
            break

        return incident



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

There are some serious caveats:

  1. You've mentioned that you want to package this for android but you seem to be using python3 syntax. As far as I know kivy only works for Android in Python2 at the moment
  2. I would recommend at least very basic error handling e.g. there's no exception handling on the web parsing.
  3. The site that you are using to gather the incidents already has xml feeds. It would be better to parse this to get the list of incidents
  4. The kivy language is far better for creating complicated GUI configurations. I would recommend moving all of the contents of the kv string into a separate file named DSFR.kv. You can then remove the Builder.loadstring line. It will also allow you to make the extra changes you mention in the question more easily
  5. I wouldn't bind the spinner directly to the web querying because it'll freeze if the web requests take a long time. I would recommend that you use a screenmanager with a separate results screen and trigger the transition with the spinner
  6. Flooding a site with multiple queries one after another is a good way to get your app and/or IP address blacklisted by the site admin. Please be careful how you do this.

Extra questions:

Community
  • 1
  • 1
tiktok
  • 456
  • 3
  • 13
  • thanks very much, i figured i was asking too many questions so will slow down thanks for the heads up! So I know about python3 not being supported yet, however i was going to wait unless making the transition back to 2 is easy enough, but while im still developing the app i really can wait. i was going to add error handeling and clean things up a bit after i got the bulk set up, i know its better as you go but i dont know enough about python as of yet or kivy. speaking of which I can use a seperate file for kivy (.kv) for the same project? i will look into all of these things! thank you again! – Raif Jackson Nov 04 '14 at 10:31
  • Glad to help. Could you accept the answer if it was what you're looking for? – tiktok Nov 04 '14 at 20:59
  • Hi, Ive had time to go through the code, its much cleaner thanks! i have had to change the loop slightly taking out the break and replacing with an if not statement as it wasnt getting more than one link, that being said i now get all the info as needed but it doenst output to the label giving "ValueError: Label.text accept only str" but incident does contain the details that i wanted just apparently not in a string? starting the error handling now. thanks again for your help – Raif Jackson Nov 06 '14 at 10:06
  • You can force it to return a string representation by using str(myobj). That might help to show what's actually being returned – tiktok Nov 07 '14 at 13:59
  • Thanks I will give it a try! can you point me to any documentation? google has failed me! – Raif Jackson Nov 10 '14 at 08:35
  • perfect thanks!! I thought that was only 2.7! duh!! works great! – Raif Jackson Nov 11 '14 at 09:51