-->

downloading the file and cancel in python

2019-08-01 06:44发布

问题:

I'm working on my python script to download a xml file from my server and write the data in a sqlite3 database in parallel.

I need some help regarding how to cancel the connection from my server using the urllib2 library. I want the database to stop writing the data away as soon as the connection ahs been cancelled. The allchannels_timer will be called when the user hits the 'enter' button, which will wait one second before connecting to my server to download the xml file. I want to download to stop when i hit the backspace button but currently, the code continues as if nothing happened.

Here is my current code:

import urllib2
import StringIO
import sqlite3
import threading
from sqlite3 import dbapi2 as database
from xml.etree import ElementTree
import xml.etree.ElementTree as ET
from UserDict import DictMixin

#get actioncodes from keyboard.xml
ACTION_ENTER = 7
ACTION_BACKSPACE = 110

def cSetVisible(WiNdOw,iD,V=True): WiNdOw.getControl(iD).setVisible(V)

class MyClass(xbmcgui.WindowXML):
     def timer1_8percent(self):
         for i in range(1):
             time.sleep(1)
             self.getControl(4202).setLabel("8%")


     def timer1_12percent(self):
         for i in range(1):
             time.sleep(2)
             self.getControl(4202).setLabel("12%")


     def timer1_18percent(self):
         for i in range(1):
             time.sleep(3)
             self.getControl(4202).setLabel("18%")


     def allchannels_timer(self):
         for i in range(1):
             time.sleep(0.3)
             self.getControl(4202).setLabel("0%")

             #DOWNLOAD THE XML SOURCE HERE
             url = ADDON.getSetting('allchannel.url')
             req = urllib2.Request(url)
             response = urllib2.urlopen(req)
             data = response.read()
             response.close()
             profilePath = xbmc.translatePath(os.path.join('special://userdata/addon_data/script.tvguide', ''))
             self.getControl(4202).setLabel("1%")
             self.thread = threading.Thread(target=self.timer1_8percent)
             self.thread.setDaemon(True)
             self.thread.start()
             self.thread = threading.Thread(target=self.timer1_12percent)
             self.thread.setDaemon(True)
             self.thread.start()
             self.thread = threading.Thread(target=self.timer1_18percent)
             self.thread.setDaemon(True)
             self.thread.start()


             if os.path.exists(profilePath):
                 profilePath = profilePath + 'source.db'
                 con = database.connect(profilePath)
                 cur = con.cursor()
                 cur.execute('CREATE TABLE programs(channel TEXT, title TEXT, start_date TIMESTAMP, stop_date TIMESTAMP, description TEXT)')
                 con.commit()
                 con.close
                 tv_elem = ElementTree.parse(StringIO.StringIO(data)).getroot()
                 profilePath = xbmc.translatePath(os.path.join('special://userdata/addon_data/script.tvguide', ''))
                 profilePath = profilePath + 'source.db'
                 con = sqlite3.connect(profilePath)
                 cur = con.cursor()
                 channels = OrderedDict()

                 # Get the loaded data
                 for channel in tv_elem.findall('channel'):
                     channel_name = channel.find('display-name').text
                     for program in channel.findall('programme'):
                         title = program.find('title').text
                         start_time = program.get("start")
                         stop_time = program.get("stop")
                         cur.execute("INSERT INTO programs(channel, title, start_date, stop_date)" + " VALUES(?, ?, ?, ?)", [channel_name, title, start_time, stop_time])
                         con.commit()
                         con.close

                 print 'Channels store into database are now successfully!'
                 program = None
                 now = datetime.datetime.now()
                 #strCh = '(\'' + '\',\''.join(channelMap.keys()) + '\')'
                 cur.execute('SELECT channel, title, start_date, stop_date FROM programs WHERE channel')
                 getprogram_info = cur.fetchall()

                 for row in getprogram_info:
                     programming = row[0], row[1], row[2], row[3]
                     print programming
                     #print row[0], row[1], row[2], row[3]
                     #programming = row[0], row[1], row[2], row[3]
                     #programming = row[0], row[1], row[2], row[3]
                     #cur.close()


def onAction(self, action):
   img1_yellow = xbmc.getCondVisibility('Control.IsVisible(3)')

   if action == ACTION_BACKSPACE:
     if img1_yellow:
       cSetVisible(self,3,True)
       self.getControl(4202).setLabel("")
       #cancel the connection and close the database


  if action == ACTION_ENTER:
     if img1_yellow:
         cSetVisible(self,3,False)
         self.thread = threading.Thread(target=self.allchannels_timer)
         self.thread.setDaemon(True)
         self.thread.start()

Can someone please tell me how I can cancel the connection from my server so that the xml file will stop being downloaded. I would further like to know how i can prevent the data from being written in my database once the connection has been cancelled.

I would be very grateful for any help regarding my problem, some example code would be highly appreciated.

回答1:

To download a file in the background, while processing events in the foreground, it's much simpler to use a Process. They have better Python support, they can do CPU in addition to I/O, and are killable if they act up.

The following starts a background process. The parent's main loop does its own thing, briefly checking if the download is done every now and then. If download is done, it continues processing, then exits.

Have fun!

source

import logging, multiprocessing, time, urllib2

def download(url):
    mylog = multiprocessing.get_logger()
    mylog.info('downloading %s', url)
    time.sleep(2)
    req = urllib2.Request(url)
    response = urllib2.urlopen(req)
    data = response.read()
    response.close()
    # more here
    time.sleep(3)
    mylog.info('done')

def main():

    mylog = multiprocessing.log_to_stderr(level=logging.INFO)
    mylog.info('start')

    download_proc = multiprocessing.Process(
        target=download,
        args=('http://example.com',),
        )
    download_proc.start()

    while True:
        mylog.info('ding')
        if download_proc.join(timeout=0.1) is None:
            mylog.info('download done!')
            break
        time.sleep(1)

    mylog.info('done!')

if __name__=='__main__':
    main()

output

[INFO/MainProcess] start
[INFO/MainProcess] ding
[INFO/Process-1] child process calling self.run()
[INFO/Process-1] downloading http://example.com
[INFO/MainProcess] download done!
[INFO/MainProcess] done!
[INFO/MainProcess] process shutting down
[INFO/MainProcess] calling join() for process Process-1
[INFO/Process-1] done
[INFO/Process-1] process shutting down
[INFO/Process-1] process exiting with exitcode 0