Combining HTML and Tkinter Text Input - html

I'm looking for some help in finding a way to construct a body of text that can be implemented within an HTML document upon users inputting their text to display in an Entry. I have figured out the following on how to execute the browser to open in a new window when clicking the button and displaying the HTML string. However, the area I am stuck on is grabbing the user input inside the wbEntry variable to function with the HTML string outputted by 'message'. I was looking at lambda's to use as a command within wbbutton, but not sure if that's the direction to look for a solution.
from tkinter import *
import webbrowser
def wbbrowser():
f = open('index.html','w')
message = "<html><head></head><body><p>This is a test</p></body</html>"
f.write(message)
f.close()
webbrowser.open_new_tab('index.html')
wbGui = Tk()
source = StringVar()
wbGui.geometry('450x450+500+300')
wbGui.title('Web Browser')
wblabel = Label(wbGui,text='Type Your Text Below').pack()
wbbutton = Button(wbGui,text="Open Browser",command = wbbrowser).pack()
wbEntry = Entry(wbGui,textvariable=source).pack()
I am using Python 3.5 and Tkinter on a Windows 7. The code above does not operate for me on my Mac OSX as that would require a different setup for my wbbrowser function. Any help would be appreciated.

Since you are associating a StringVar with the entry widget, all you need to do is fetch the value from the variable before inserting it into the message.
def wbbrowser():
...
text = source.get()
message = "<html><head></head><body><p>%s</p></body</html>" % text
...

Related

Selenium, using find_element but end up with half the website

I finished the linked tutorial and tried to modify it to get somethings else from a different website. I am trying to get the margin table of HHI but the website is coded in a strange way that I am quite confused.
I find the child element of the parent that have the text with xpath://a[#name="HHI"], its parent is <font size="2"></font> and contains the text I wanted but there is a lot of tags named exactly <font size="2"></font> so I can't just use xpath://font[#size="2"].
Attempt to use the full xpath would print out half of the website content.
the full xpath:
/html/body/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[3]/td/pre/font/table/tbody/tr/td[2]/pre/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font/font
Is there anyway to select that particular font tag and print the text?
website:
https://www.hkex.com.hk/eng/market/rm/rm_dcrm/riskdata/margin_hkcc/merte_hkcc.htm
Tutorial
https://www.youtube.com/watch?v=PXMJ6FS7llk&t=8740s&ab_channel=freeCodeCamp.org
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
import pandas as pd
# prepare it to automate
from datetime import datetime
import os
import sys
import csv
application_path = os.path.dirname(sys.executable) # export the result to the same file as the executable
now = datetime.now() # for modify the export name with a date
month_day_year = now.strftime("%m%d%Y") # MMDDYYYY
website = "https://www.hkex.com.hk/eng/market/rm/rm_dcrm/riskdata/margin_hkcc/merte_hkcc.htm"
path = "C:/Users/User/PycharmProjects/Automate with Python – Full Course for Beginners/venv/Scripts/chromedriver.exe"
# headless-mode
options = Options()
options.headless = True
service = Service(executable_path=path)
driver = webdriver.Chrome(service=service, options=options)
driver.get(website)
containers = driver.find_element(by="xpath", value='') # or find_elements
hhi = containers.text # if using find_elements, = containers[0].text
print(hhi)
Update:
Thank you to Conal Tuohy, I learn a few new tricks in Xpath. The website is written in a strange way that even with the Xpath that locate the exact font tag, the result would still print all text in every following tags.
I tried to make a list of different products by .split("Back to Top") then slice out the first item and use .split("\n"). I will .split() the lists within list until it can neatly fit into a dataframe with strike prices as index and maturity date as column.
Probably not the most efficient way but it works for now.
product = "HHI"
containers = driver.find_element(by="xpath", value=f'//font[a/#name="{product}"]')
hhi = containers.text.split("Back to Top")
# print(hhi)
hhi1 = hhi[0].split("\n")
df = pd.DataFrame(hhi1)
# print(df)
df.to_csv(f"{product}_{month_day_year}.csv")
You're right that HTML is just awful! But if you're after the text of the table, it seems to me you ought to select the text node that follows the B element that follows the a[#name="HHI"]; something like this:
//a[#name="HHI"]/following-sibling::b/following-sibling::text()[1]
EDIT
Of course that XPath won't work in Selenium because it identifies a text node rather than an element. So your best result is to return the font element that directly contains the //a[#name="HHI"], which will include some cruft (the Back to Top link, etc) but which will at least contain the tabular data you want:
//a[#name="HHI"]/parent::font
i.e. "the parent font element of the a element whose name attribute equals HHI"
or equivalently:
//font[a/#name="HHI"]
i.e. "the font element which has, among its child a elements, one whose name attribute equals HHI"

HTML Dec Code image in Tkinter label — either text or image is doubled

I'd like to add a picture to some of my tkinter labels, and I found a page with many of them (there are, of course, many similar pages), including some that I want.
But I'm having a strange behavior with this.
The code
import tkinter as tk
from tkinter import ttk
import html
root = tk.Tk()
root.geometry("200x100")
s = html.unescape('&#127937') # chequered flag
text = "some text"
label_text = "{}{}".format(text, s)
my_label = ttk.Label(root, text=label_text)
my_label.pack()
t = chr(9917)
another = "football ball"
another_text = "{}{}".format(t, another)
another_label = ttk.Label(root, text=another_text)
another_label.pack()
root.mainloop()
produces the following window:
On the other hand, if I replace label_text = "{}{}".format(text, s) with label_text = "{}{}".format(s, text) the flag appears twice instead (once before "some text" and another after).
Apparently this only happens with html images.
For example, with the second label, I have the expected behavior.
Is there something I'm doing wrong here, or should I just avoid these images in tkinter?
i wouldnt avoid them yet i wouldnt advise them either. Because tkinter propbably uses regular images its propbably not used to emojis. My recommendation is to use regular images instead of emojis.

For Loop in A Set Of Elements in Selenium Python

I'm trying to automate one of my manual tasks. I have written the complete script but I am stuck at a point where For Loop is not working.
Here is what I want to do:
This is the set of cards that I want to loop through and perform some actions. For testing purposes, I am just trying to print the title of all the products.
This is the main code of the image attached before. The class = 'm--t--1' is the main element that contains all these products.
And below is the code for a single product.
Now, this is my code which I have written. NOTE: This is not the complete script. I have just written the part of the script where I'm having a problem.
#Logging into the website with credentials and saved cookies!
driver.get("https://poshmark.com/login")
time.sleep(5)
driver.maximize_window()
time.sleep(5)
cookies = pickle.load(open("cookies.pkl", "rb"))
for cookie in cookies:
driver.add_cookie(cookie)
time.sleep(5)
driver.find_element_by_xpath('//*[#id="login_form_username_email"]').send_keys('email hidden')
time.sleep(5)
driver.find_element_by_xpath('//*[#id="login_form_password"]').send_keys('password hidden')
time.sleep(5)
driver.find_element_by_xpath('//*[#id="email-login-form"]/div[4]/button').click()
#Navigating to the closet where these products can be found.
driver.find_element_by_xpath('//*[#id="app"]/header/nav[1]/div/ul/li[5]/div/div[1]').click()
driver.find_element_by_xpath('//*[#id="app"]/header/nav[1]/div/ul/li[5]/div/div[2]/ul/li[1]/a').click()
container_of_products = driver.find_elements_by_class_name('tile col-x12 col-l6 col-s8 p--2')
for item in container_of_products:
listing = item.find_element_by_tag_name('a')
print(listing.text)
driver.execute_script("window.history.go(-1)")
tile col-x12 col-l6 col-s8 p--2 is a compound class name it won't work that way. use a css selector and .tile.col-x12.col-l6.col-s8.p--2
container = driver.find_elements_by_css_selector('.tile.col-x12.col-l6.col-s8.p--2')

How to vertically align comma separated values in Notepad++?

As shown in the picture "Before" below, each column separated by comma is not aligned neatedly. Is there any method to align each column vertically like the display effect in Excel?
The effect I wish is shown in the picture "After".
Thanks to #Martin S , I can align the file like the picture "Method_1". As he has mentioned, some characters still cannot align well. I was wondering if this method could be improved?
You can use the TextFX plugin:
TextFX > TextFX Edit > Line up multiple lines by ...
Note: This doesn't work if the file is read only.
http://tomaslind.net/2016/02/18/how-to-align-columns-in-notepad/
Update 2019: Download link from SourceForge
Maybe not exactly what you're looking for, but I recently added a CSV Lint plug-in to Notepad++ which also adds syntax highlighting for csv and fixed width data files, meaning each column gets a different color so it's easier to see.
You can use this python plugin script which utilizes the csv library which takes care of quoted csv and many other variants.
Setup:
Use the plugin manager in Notepad++ to install the "Python script" plugin.
Plugins->Python Script->New Script (name it something like CSVtoTable.py)
Paste the following python script into the new file and save:
CSVtoTable.py
import csv
inputlines = editor.getText().split('\n')
# Get rid of empty lines
inputlines = [line.strip() for line in inputlines if line.strip()]
reader = csv.reader(inputlines, delimiter=',')
csvlist = [line for line in reader]
# transpose to calculate the column widths and create a format string which left aligns each row
t_csvlist = zip(*csvlist)
col_widths = [max([len(x) for x in t_csvlist[y]]) for y in range(len(t_csvlist))]
# To right align - change < to >
fmt_str = ' '.join(['{{:<{0}}}'.format(x) for x in col_widths]) + '\r\n'
text = []
for line in csvlist:
text.append(fmt_str.format(*line))
# open a new document and put the results in there.
notepad.new()
editor.addText(''.join(text))
Open your CSV file in notepad++
Click on Plugins->Python Script->Scripts->(The name you used in step 2)
A new tab with the formatted data should open.
Update (right aligned numbers & left aligned strings):
Use the following python script if you want to right align number fields from the CSV - it looks at the second line of the csv to determine the types of the fields.
import csv
import re
num_re = re.compile('[-\+]?\d+(\.\d+)?')
inputlines = editor.getText().split('\n')
# Get rid of empty lines
inputlines = [line.strip() for line in inputlines if line.strip()]
reader = csv.reader(inputlines, delimiter=',')
csvlist = [line for line in reader]
# Transpose to calculate the column widths and create a format string which left aligns each row
t_csvlist = zip(*csvlist)
col_widths = [max([len(x) for x in t_csvlist[y]]) for y in range(len(t_csvlist))]
# Numbers get right aligned
type_eval_line = csvlist[1 if len(csvlist)>1 else 0]
alignment = ['>' if num_re.match(item) else '<' for item in type_eval_line]
# Compute the format string
fmt_str = ' '.join(['{{:{0}{1}}}'.format(a,x) for x,a in zip(col_widths,alignment)]) + '\r\n'
text = []
for line in csvlist:
text.append(fmt_str.format(*line))
# open a new document and put the results in there.
notepad.new()
editor.addText(''.join(text))
Notepad++ CSVLint
Install CSVLint Plugin
Open CSV file. Or manually set Language > CSVLint. This will give you nicely colored output.
To reformat do this:
Open lower pane: Plugins > CSV Lint > CSV Lint Window.
Click the Reformat button. Check the box Align vertically (not recommended). -- This may screw up your data, so think twice before clicking OK.
Reformatted output:
If you want to try this yourself: Here is my sample input:
TIMESTAMP_START,TIMESTAMP_END,TA_ERA,TA_ERA_NIGHT,TA_ERA_NIGHT_SD,TA_ERA_DAY,DA_ERA_DAY_SD,SW_IN_ERA,HH,DD,WW-YY,SW_IN_F,HH
19890101,19890107,3.436,1.509,2.165,6.134,2.889,100.233,283.946,1.373,99.852,2.748,1.188
19890108,19890114,3.814,2.446,2.014,5.728,2.526,91.708,286.451,1.575,100,100.841,0.742
You could use Search&Replace to change all occurrences of , to ,\t. This will add a tab after each ,.
This method has however some drawbacks:
you effectively add white-space characters to your document (in case you need to edit and save it).
This works well only if the difference (in terms of number of characters) between the longest and the shortest numbers is less than 1 tab-size (usually 4 characters).

Setting the content of a span element,populated from a list using selenium

I am trying to set the content of a span element using selenium but seems it is not getting set as the value. The span field is a value which is filled in from a list as the user types in.
Further details on the problem
1)Go to http://www.goeuro.es.
2)Tried setting the destination field as under:
a)If the user types berlin in the destination field,it gets replaced by the text (this is getting populating from their js)
Berlín Alemania
I tried setting this using the following code.
#FindBy(xpath = ".//*[#id='$desktopSearchform']/div[1]/div[2]/d-departure-position/div/div/div/span[1]")
private WebElement fromSearchFieldSpan1;
#FindBy(xpath = ".//*[#id='$desktopSearchform']/div[1]/div[2]/d-departure-position/div/div/div/span[2]")
private WebElement fromSearchFieldSpan2;
.
.
.
.
((JavascriptExecutor)driver).executeScript("arguments[0].innerHTML = 'Berlín'", fromSearchFieldSpan1);
((JavascriptExecutor)driver).executeScript("arguments[0].innerHTML = 'Alemania'", fromSearchFieldSpan2);
When I tried with the above provided code,it seemed as it set the text as the title of the said fields as I was getting a input validation error upon submitting the page(as if these values were not entered at all).
Screenshot attached.
I can't set the value of this field using sendKeys() since this is not a text field.
Any thoughts how this can be set using selenium web driver.?
You're trying to handle span element while you should handle input. Try below code:
#FindBy(xpath = "//input[#id='$city']")
private WebElement fromSearchFieldSpan;
fromSearchFieldSpan.sendKeys('Berlin Alemania')