Azam
Azam

Reputation: 13

flask ValueError: I/O operation on closed file

I have a code which i am using to scrape from a web page and I am saving the scraped data in a html file and displaying it as a different page. below is the code

from flask import Flask, render_template,request from bs4 import
BeautifulSoup import urllib.request import sys,os app =
Flask(__name__) @app.route('/') def index():
    return render_template ('index.html')

@app.route('/result',methods = ['POST']) def result():    if
request.method == 'POST':
      result = request.form.get("search")
      link = "https://xyz.comindex?search="
      url = (link+result)
      print(url)
      try:
         page = urllib.request.urlopen(url)
         soup = BeautifulSoup(page, 'html.parser')
         test = soup.findAll('div', attrs={"class": "search-inner-wrapper"})
         sys.stdout = open("tests.html", "w")
         print(test)
         sys.stdout.close()
         return render_template("SearchResults.html", test=test)
      except:
         print("An error occured.")
      return render_template("test.html", test=test)


if __name__ == '__main__':
    app.run(use_reloader = True, debug = True)

My problem is that this code works perfectly fine but just for once, When i reload the index page and perform a search query I get

ValueError: I/O operation on closed file.

I cant figure a work around for this since i have to use single file every time and do not want the results to append with existing code.

Upvotes: 0

Views: 1217

Answers (1)

Brenda J. Butler
Brenda J. Butler

Reputation: 1485

You are redefining sys.stdout to be the file handle of the file you opened. Use another name, don't overwrite sys.stdout. And don't close sys.stdout. It's ok to close the file handle you create though.

Example of opening a file and reading it, opening a file and writing it:

bjb@blueeyes:~$ cat /tmp/infile.html
<html>
<head>
</head>
<body>
<div class="search-inner-wrapper">fleeble flobble</div>
</body>
</html>
bjb@blueeyes:~$ cat /tmp/file2.py
#!/usr/bin/env python3


with open('/tmp/infile.html', 'r') as infile:
    page = infile.readlines()

with open('/tmp/outfile.html', 'w') as ofd:
    ofd.write(''.join(page))


bjb@blueeyes:~$ /tmp/file2.py
bjb@blueeyes:~$ cat /tmp/outfile.html
<html>
<head>
</head>
<body>
<div class="search-inner-wrapper">fleeble flobble</div>
</body>
</html>

The first line of /tmp/file2.py just says this is a python script.

The next two lines open a file called /tmp/infile.html for reading and declare a variable "infile" as the read file descriptor. Then all the lines in /tmp/infile.html are read into a list of strings.

When we leave that "with" block, the file is closed for us.

Then in the next two lines, we open /tmp/outfile.html for writing and we use the variable ofd ("output file descriptor") to hold the file descriptor. We use ofd to write the series of lines in the list "page" to that file. Once we leave that second "with" block, the output file is closed for us. Then the program exits ... my last command dumps out the contents of /tmp/outfile.html, which you can see is the same as infile.html.

If you want to open and close files without using those with blocks, you can:

infile = open('/tmp/infile.html', 'r')
page = infile.readlines()
infile.close()

ofd = open('/tmp/outfile.html', 'w')
ofd.write(''.join(page))
ofd.close()

Hopefully that will work in a flask script ...

Upvotes: 2

Related Questions