外部文件类的函数问题:"NoneType"对象没有属性"iloc"



我有一个窗口,可以在文本框中打印新闻内容。您必须首先点击";查看标题"按钮,然后选择标题,最后点击";查看内容";按钮它工作正常,没有任何问题。

在这个问题中,我已经将窗口代码放置在一个外部文件(page1.py)的类中。该文件将在主文件(main.py)中打开。如果我点击";查看标题"按钮,它工作得很好,但如果我点击";查看内容";按钮我在函数def content:中得到一个错误

item = df.iloc[selection[-1]]
AttributeError: 'NoneType' object has no attribute 'iloc'

我希望当我点击";查看内容";按钮,新闻内容将打印在文本框中。正如我上面所说的,当代码在一个只有一个窗口的简单文件中时。。。它运行得很好,而现在如果放在外部类中,我会遇到问题。

我是Python的新手。你能给我看看答案中的代码吗?否则我可能不理解,谢谢和抱歉

Main.py

import tkinter as tk
from tkinter import ttk
from PIL import ImageTk
from page1 import Page1
root = tk.Tk()
root.geometry('480x320')
topbar = tk.Frame(root, bg='#e10a0a', height=43)
topbar.pack(fill='x')
style = ttk.Style()
style.theme_use('default') # select a theme that allows configuration of ttk.Notebook
# put the tabs at the left with white background
style.configure('TNotebook', tabposition='wn', background='white', tabmargins=0)
# configure tab with white background initially, yellow background when selected
style.configure('TNotebook.Tab', background='white', width=10, focuscolor='yellow', borderwidth=0)
style.map('TNotebook.Tab', background=[('selected', 'yellow')])
nb = ttk.Notebook(root)
nb.pack(fill='both', expand=1)
page1 = Page1(nb)
nb.add(page1, text='aaaaa', compound='left')
root.mainloop()

第1.py页

import tkinter as tk
from tkinter import ttk
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.font as tkFont
from tkinter import ttk
import tkinter as tk   # PEP8: `import *` is not preferred
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText 
import requests
import requests_cache 
from bs4 import BeautifulSoup
import pandas as pd
import re
import json
from dateutil import parser
import datetime
import locale

class Page1(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)

def get_data_for(place):
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'
}
results = []
response = requests.get(f'https://www.tuttomercatoweb.com/{place}/', headers=headers)
print('url:', response.url)
print('status:', response.status_code)
#print('html:', response.text[:1000])
soup = BeautifulSoup(response.content, 'html.parser')
#Cover
cover_news = soup.find('div', {'class':'box pp'})
link = cover_news.find('a', href=True)['href']
coverNewsResponse = requests.get(link, headers=headers)
coverSoup = BeautifulSoup(coverNewsResponse.content, 'html.parser')
jsonStr = str(coverSoup.find('script'))
jsonStr = re.search('({.*})', jsonStr).group(1)
jsonData = json.loads(jsonStr)

timePublished = parser.parse(jsonData['datePublished']).strftime("%H:%M")
datePublished = parser.parse(jsonData['datePublished']).strftime("%Y-%m-%d")
title = jsonData['headline']
news = f" {timePublished} {place.upper()}, {title} (TMW)"
results.append( [datePublished, timePublished, place, title, news, link] )
# Side panel
side_news = soup.find_all('div', {'class':'box small'})
for each in side_news:
link = each.find('a', href=True)['href']
sideNewsResponse = requests.get(link, headers=headers)
sideSoup = BeautifulSoup(sideNewsResponse.content, 'html.parser')
jsonStr = str(sideSoup.find('script'))
jsonStr = re.search('({.*})', jsonStr).group(1)
jsonData = json.loads(jsonStr)

timePublished = parser.parse(jsonData['datePublished']).strftime("%H:%M")
datePublished = parser.parse(jsonData['datePublished']).strftime("%Y-%m-%d")
title = jsonData['headline']
news = f" {timePublished} {place.upper()}, {title} (TMW)"
results.append( [datePublished, timePublished, place, title, news, link] )


news = soup.find_all('div', attrs={"class": "tcc-list-news"})
for each in news:
for div in each.find_all("div"):
timePublished  = div.find('span', attrs={'class': 'hh serif'}).text
datePublished = div.find_previous('div', {'class':'tcc-border upper date'})

if datePublished:
if datePublished.text in ['Ieri']:
yesterday = datetime.datetime.today() - datetime.timedelta(days = 1)
datePublished = yesterday.strftime("%Y-%m-%d")
else:
locale.setlocale(locale.LC_ALL, '') #locale.setlocale(locale.LC_ALL, 'it')
currentYear = datetime.datetime.today().strftime("%Y")
dateStr = datePublished.text
dateStr = datetime.datetime.strptime(dateStr + ' ' + currentYear, '%A %d %B %Y')
datePublished = dateStr.strftime("%Y-%m-%d")
else:
datePublished = datetime.datetime.today().strftime("%Y-%m-%d")

title = " ".join(span.text for span in div.select("a > span"))
news = f" {timePublished} {place.upper()}, {title} (TMW)"
link  = div.find('a')['href']
results.append( [datePublished, timePublished, place, title, news, link] )
return results
def all_titles():
global df
allnews = []  # local variable
for place in ['atalanta',  'bologna']:
print('search:', place)
results = get_data_for(place)
print('found:', len(results))
allnews += results
text_download.insert('end', f"search: {place}nfound: {len(results)}n")
df = pd.DataFrame(allnews, columns=['date', 'time', 'place', 'title', 'news', 'link'])
df = df.sort_values(by=['date', 'time', 'place', 'title'], ascending=[False, False, True, True])
df = df.drop_duplicates(subset=['date', 'time', 'place', 'title'])
df = df.reset_index(drop=True)
listbox_title.delete('0', 'end')
for index, row in df.iterrows():
listbox_title.insert('end', row['news'])
def content(event=None):   # `command=` executes without `event`, but `bind` executes with `event` - so it needs default value
# tuple
selection = listbox_title.curselection()
print('selection:', selection)
if selection:
item = df.iloc[selection[-1]]
#print('item:', item)
url = item['link']
#print('url:', url)
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'
}
# keep page in database `SQLite` 
# https://github.com/reclosedev/requests-cache
# https://sqlite.org/index.html
session = requests_cache.CachedSession('titles')
response = session.get(url, headers=headers)
#response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')
content_download = "n".join(item.get_text() for item in soup.select("div.text.mbottom"))
text_download.delete('1.0', 'end') # remove previous content)
text_download.insert('end', content_download)
# --- main ---
df = None
# window = tk.Tk()
# window.geometry("800x800")
frame_title = tk.Frame(self)
frame_title.pack(fill='both', expand=True, pady=5, padx=5)
listbox_title = tk.Listbox(frame_title, selectbackground="#960000", selectforeground="white", bg="white")
listbox_title.pack(side='left', fill='both', expand=True)
scrollbar_title = tk.Scrollbar(frame_title)
scrollbar_title.pack(side='left', fill='y')
scrollbar_title['command'] = listbox_title.yview
listbox_title.config(yscrollcommand=scrollbar_title.set)
listbox_title.bind('<Double-Button-1>', content)  # it executes `content(event)`
# ----
text_download = ScrolledText(self, bg="white")
text_download.pack(fill='both', expand=True, pady=0, padx=5)
# ----
buttons_frame = tk.Frame(self)
buttons_frame.pack(fill='x')
button1 = tk.Button(buttons_frame, text="View Titles", command=all_titles)  # don't use `[]` to execute functions
button1.pack(side='left', pady=5, padx=5)
button2 = tk.Button(buttons_frame, text="View Content", command=content)   # don't use `[]` to execute functions
button2.pack(side='left', pady=5, padx=(0,5))

解决此问题的简单方法是在all_titles()函数中将global df更改为nonlocal df

但是,我建议使用实例变量,将所有df更改为self.df:

class Page1:
def __init__(self, master, **kw):
...
def all_titles():
...
# changed df to self.df
self.df = pd.DataFrame(allnews, columns=['date', 'time', 'place', 'title', 'news', 'link'])
self.df = self.df.sort_values(by=['date', 'time', 'place', 'title'], ascending=[False, False, True, True])
self.df = self.df.drop_duplicates(subset=['date', 'time', 'place', 'title'])
self.df = self.df.reset_index(drop=True)
listbox_title.delete('0', 'end')
for index, row in self.df.iterrows():
listbox_title.insert('end', row['news'])
def content(event=None):
...
if selection:
item = self.df.iloc[selection[-1]]
...
...
self.df = None
...

我认为您已经声明df是嵌套在__init__方法下的一个函数中的全局变量。。。然后在稍后的主要部分(实际上在__init__中运行(中,将df设置为None。在使变量成为全局变量时,您需要更加小心,并更多地考虑函数范围;您定义的那些函数需要在__init__的范围内吗?或者它们可以有不同的范围吗?

最新更新