I have a tuple in the format (Name, email, units sold). I would like to generate an HTML table, grouped by Name and then embed that table into an email through Outlook.
My Code:
from itertools import groupby
from operator import itemgetter
import win32com.client
mytuple = [('Andrew','Andrew#gmail.com','20'),('Jim',"Jim#gmail.com",'12'),("Sarah","Sarah#gmail.com",'43'),("Jim","Jim#gmail.com",'15'),("Andrew","Andrew#gmail.com",'56')]
mytuple = sorted(mytuple)
FULL_HTML = []
for name, rows in groupby(mytuple, itemgetter(0)):
table = []
for name, value2 in rows:
table.append(
"<tr><td>{}</td><td>{}</td></tr>".format(
name, value2 ))
html_code = "<html><table>" + str(table) + "</table></html>"
olMailItem = 0x0
obj = win32com.client.Dispatch("Outlook.Application")
newMail = obj.CreateItem(olMailItem)
newMail.Subject = "This is the subject"
newMail.HTMLBody = html_code
newMail.To = "sampleemail#gmail.com"
newMail.Display()
Desired output:
This would open 3 emails with HTML code in their body.
Email 1:
<html>
<table>
<tr><td>Andrew</td><td>20</td><td></tr>
<tr><td>Andrew</td><td>56</td><td></tr>
</table>
</html>
Email 2:
<html>
<table>
<tr><td>Jim</td><td>12</td><td></tr>
<tr><td>Jim</td><td>15</td><td></tr>
</table>
</html>
Email 3:
<html>
<table>
<tr><td>Sarah</td><td>43</td><td></tr>
</table>
</html>
Here's your problem:
for name, value2 in rows:
table.append(
"<tr><td>{}</td><td>{}</td></tr>".format(
name, value2 ))
Change this to:
for n, e, id in rows:
table.append(
"<tr><td>{}</td><td>{}</td></tr>".format(
n, id ))
html_code = "<html><table>" + ''.join(table) + "</table></html>"
The groupby function still returns 3-tuples.
Related
I am trying to query a list from my Flask database and then send it out as a html email. However, i am unable to break them into different lines.
for example, instead of:
a
b
c
i get abc currently in the email. i've tried adding "\n" in the loop but it doesnt seem to work. does anyone know how i can break it into different rows?
def mail():
sender_email = "xx#gmail.com"
message = MIMEMultipart("alternative")
message["Subject"] = "xx"
message["From"] = sender_email
message["To"] = user_mail
add = '\n'
list = Lines.query.all()
for s in list:
add += str(s.title) + '\r\n'
print(add)
# Write the plain text part
text = "Thank you for submitting a xx! Here are the lines submitted: " + add
# write the HTML part
html = """\
<html>
<head><head style="margin:0;padding:0;">
<table role="presentation" style="width:100%;border-collapse:collapse;border:20;border-spacing:20;background:#cc0000;">
<tr>
<td align="center" style="padding:20;color:#ffffff;">
Your xxxxx was submitted!
</td>
</tr>
</table>
</head>
<p>Thank you for submitting a xx! Here are the lines submitted for your reference:<br><br>
""" + add + """
<br></br>
</p>
</html>
"""
# convert both parts to MIMEText objects and add them to the MIMEMultipart message
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)
...
server.sendmail("xx#gmail.com", user_mail, message.as_string())
return redirect(url_for('complete'))
I believe what you're looking for is this:
list = Lines.query.all()
for s in list:
add += str(s.title) + '<br>'
or (using format vs string concatenation):
list = Lines.query.all()
for s in list:
add += '{}<br>'.format(str(s.title))
or (python 3.6+ f strings):
list = Lines.query.all()
for s in list:
add += f"{s.title}<br>"
\n is not for HTML, but <br> is.
You can use an empty string and keep adding in the loop.
str = ""
for s in list:
str += f"{s.title}\n"
I'm trying to print the data of a CSV column into an HTML table
CSV file is like this (sample)
firstname, surname
firstname, surname
firstname, surname
firstname, surname
firstname, surname
firstname, surname
firstname, surname
I can read this data in ok - and get it to print out into a table via the following:
import csv
import sys
from fpdf import FPDF, HTMLMixin
#load in csv file
data = csv.reader(open(sys.argv[1]))
names = ""
#Read column names from first line of the file
fields = data.next()
for row in data:
names = row[0] + " " + row[1]
html_row = " <tr> "
html_col = " <td border=0 width=15%>" + names + "</td></tr>"
html_out = html_out + html_row + html_col
html = html_header + html_out + html_footer
print html
pdf.write_html(html)
pdf.output('test2.pdf', 'F')
this gives the following:
<tr><td border=0 width=15%>firstname surname</td></tr>
<tr><td border=0 width=15%>firstname surname</td></tr>
<tr><td border=0 width=15%>firstname surname</td></tr>
ie - every name is on a separate row - what i'd like to do is have every name as a cell column cell
<tr><td border=0 width=15%>firstname surname</td><td border=0 width=15%>firstname surname</td><td border=0 width=15%>firstname surname</td></tr>
thanks
Some variables in sample are not set, but this is due to reducing of sample to aminimal size I guess, so if you fill in these details, the following should work (suboptimal if more than 7 entries due to the hardcoded 15% width on the html td element.
import csv
import sys
from fpdf import FPDF, HTMLMixin
# load in csv file
data = csv.reader(open(sys.argv[1]))
# Read column names from first line of the file to ignore them
fields = data.next()
Below the loop from question has been replaced by a list comprehension.
cell_att holds the given attributes of the table cell elements and it will be interpolated like row[0] and row[1] into the strings making up the html_out list.
cell_att = " border=0 width=15%"
row_data = ["<td%s>%s %s</td>" % (cell_att, row[0], row[1]) for row in data]
Here one simply joins all cells and injects into a html table row element:
html_out = "<tr>" + "".join(row_data) + "</tr>"
html = html_header + html_out + html_footer
print html
pdf.write_html(html)
pdf.output('test2.pdf', 'F')
The other answers also give IMO useful hints esp. on the styling level of the HTML. In case you later decide to digest / transform more than 7 names, the above code might be a good start to create rows with at most 7 cells or to adapt the width attribute value by minor modifications.
You only need one <tr> to make a single row.
table, td {
border: solid 1px #CCC;
}
<table>
<tr>
<td>firstname surname</td>
<td>firstname surname</td>
<td>firstname surname</td>
</tr>
</table>
In order to make this work in your code, you need to create you row outside the loop:
html_row = '<tr>' # open row
for row in data:
names = row[0] + " " + row[1]
# append columns to the row
html_row += "<td border=0 width=15%>" + names + "</td>"
html_row += '</tr>' # close row
html_out = html_row
I have a text file that contains :
JavaScript 0
/AA 0
OpenAction 1
AcroForm 0
JBIG2Decode 0
RichMedia 0
Launch 0
Colors>2^24 0
uri 0
I wrote this code to convert the text file to html :
contents = open("C:\\Users\\Suleiman JK\\Desktop\\Static_hash\\test","r")
with open("suleiman.html", "w") as e:
for lines in contents.readlines():
e.write(lines + "<br>\n")
but the problem that I had in html file that in each line there is no space between the two columns:
JavaScript 0
/AA 0
OpenAction 1
AcroForm 0
JBIG2Decode 0
RichMedia 0
Launch 0
Colors>2^24 0
uri 0
what should I do to have the same content and the two columns like in text file
Just change your code to include <pre> and </pre> tags to ensure that your text stays formatted the way you have formatted it in your original text file.
contents = open"C:\\Users\\Suleiman JK\\Desktop\\Static_hash\\test","r")
with open("suleiman.html", "w") as e:
for lines in contents.readlines():
e.write("<pre>" + lines + "</pre> <br>\n")
This is HTML -- use BeautifulSoup
from bs4 import BeautifulSoup
soup = BeautifulSoup()
body = soup.new_tag('body')
soup.insert(0, body)
table = soup.new_tag('table')
body.insert(0, table)
with open('path/to/input/file.txt') as infile:
for line in infile:
row = soup.new_tag('tr')
col1, col2 = line.split()
for coltext in (col2, col1): # important that you reverse order
col = soup.new_tag('td')
col.string = coltext
row.insert(0, col)
table.insert(len(table.contents), row)
with open('path/to/output/file.html', 'w') as outfile:
outfile.write(soup.prettify())
That is because HTML parsers collapse all whitespace. There are two ways you could do it (well probably many more).
One would be to flag it as "preformatted text" by putting it in <pre>...</pre> tags.
The other would be a table (and this is what a table is made for):
<table>
<tr><td>Javascript</td><td>0</td></tr>
...
</table>
Fairly tedious to type out by hand, but easy to generate from your script. Something like this should work:
contents = open("C:\\Users\\Suleiman JK\\Desktop\\Static_hash\\test","r")
with open("suleiman.html", "w") as e:
e.write("<table>\n")
for lines in contents.readlines():
e.write("<tr><td>%s</td><td>%s</td></tr>\n"%lines.split())
e.write("</table>\n")
You can use a standalone template library like mako or jinja. Here is an example with jinja:
from jinja2 import Template
c = '''<!doctype html>
<html>
<head>
<title>My Title</title>
</head>
<body>
<table>
<thead>
<tr><th>Col 1</th><th>Col 2</th></tr>
</thead>
<tbody>
{% for col1, col2 in lines %}
<tr><td>{{ col 1}}</td><td>{{ col2 }}</td></tr>
{% endfor %}
</tbody>
</table>
</body>
</html>'''
t = Template(c)
lines = []
with open('yourfile.txt', 'r') as f:
for line in f:
lines.append(line.split())
with open('results.html', 'w') as f:
f.write(t.render(lines=lines))
If you can't install jinja, then here is an alternative:
header = '<!doctyle html><html><head><title>My Title</title></head><body>'
body = '<table><thead><tr><th>Col 1</th><th>Col 2</th></tr>'
footer = '</table></body></html>'
with open('input.txt', 'r') as input, open('output.html', 'w') as output:
output.writeln(header)
output.writeln(body)
for line in input:
col1, col2 = line.rstrip().split()
output.write('<tr><td>{}</td><td>{}</td></tr>\n'.format(col1, col2))
output.write(footer)
I have added title, looping here line by line and appending each line on < tr > and < td > tags, it is should work as single table without column. No need to use these tags(< tr >< /tr > and < td >< /td >[gave a spaces for readability]) for col1 and col2.
log: snippet:
MUTHU PAGE
2019/08/19 19:59:25 MUTHUKUMAR_TIME_DATE,line: 118 INFO | Logger
object created for: MUTHUKUMAR_APP_USER_SIGNUP_LOG 2019/08/19 19:59:25
MUTHUKUMAR_DB_USER_SIGN_UP,line: 48 INFO | ***** User SIGNUP page
start ***** 2019/08/19 19:59:25 MUTHUKUMAR_DB_USER_SIGN_UP,line: 49
INFO | Enter first name: [Alphabet character only allowed, minimum 3
character to maximum 20 chracter]
html source page:
'''
<?xml version="1.0" encoding="utf-8"?>
<body>
<table>
<p>
MUTHU PAGE
</p>
<tr>
<td>
2019/08/19 19:59:25 MUTHUKUMAR_TIME_DATE,line: 118 INFO | Logger object created for: MUTHUKUMAR_APP_USER_SIGNUP_LOG
</td>
</tr>
<tr>
<td>
2019/08/19 19:59:25 MUTHUKUMAR_DB_USER_SIGN_UP,line: 48 INFO | ***** User SIGNUP page start *****
</td>
</tr>
<tr>
<td>
2019/08/19 19:59:25 MUTHUKUMAR_DB_USER_SIGN_UP,line: 49 INFO | Enter first name: [Alphabet character only allowed, minimum 3 character to maximum 20 chracter]
'''
CODE:
from bs4 import BeautifulSoup
soup = BeautifulSoup(features='xml')
body = soup.new_tag('body')
soup.insert(0, body)
table = soup.new_tag('table')
body.insert(0, table)
with open('C:\\Users\xxxxx\\Documents\\Latest_24_may_2019\\New_27_jun_2019\\DB\\log\\input.txt') as infile:
title_s = soup.new_tag('p')
title_s.string = " MUTHU PAGE "
table.insert(0, title_s)
for line in infile:
row = soup.new_tag('tr')
col1 = list(line.split('\n'))
col1 = [ each for each in col1 if each != '']
for coltext in col1:
col = soup.new_tag('td')
col.string = coltext
row.insert(0, col)
table.insert(len(table.contents), row)
with open('C:\\Users\xxxx\\Documents\\Latest_24_may_2019\\New_27_jun_2019\\DB\\log\\output.html', 'w') as outfile:
outfile.write(soup.prettify())
I have the HTMl code #http://pastie.org/8456333 as a reference ,also I have the below code where i am construcing HTML code to email ..i need inputs or suggestions on what modifcations need to be done to below code to make the table look like
the HTML code #http://pastie.org/8456333
import re
import os
import sys
import time
from email.mime.text import MIMEText
import subprocess
from subprocess import check_call,Popen,PIPE
def email (body,subject,to=None):
msg = MIMEText("%s" % body)
msg["Content-Type"] = "text/html"
msg["From"] = "cdit#company.com"
#msg["From"] = "test#company.com"
if to!=None:
to=to.strip()
#msg["To"] = "test#company.com"
msg["To"] = to
else:
msg["To"] = to
msg["Subject"] = '%s' % subject
p = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE)
p.communicate(msg.as_string())
def manifest_table(project,branch):
global table_items
global tableProperties
table_items = table_items + "<tr><td>%s</td><td>%s</td></tr>"%(project,branch)
tableBody = """\
<style type="text/css">
%s
</style>
<table id="tfhover" class="tftable" border="1">
%s
</table>
"""%(tableProperties, table_items)
return tableBody
def main ():
i=0
global table_items
table_items = "<tr><th>Project</th><th>Branch</th></tr>"
global tableProperties
tableProperties = r"table.tftable {font-size:12px;color:#333333;width:10%;border-width: 1px;border-color: #729ea5;border-collapse: collapse;} table.tftable th {font-size:12px;background-color:#ded0b0;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;text-align:left;} table.tftable tr {background-color:#ffffff;} table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #729ea5;}"
project_list=['data','modem','1x','umts']
branch_list=['jb','fr','kk','choc']
for proj in project_list:
branch = branch_list[i]
mft = manifest_table(proj,branch)
i=i+1
email_body = """\
<html>
<head></head>
<body>
<p>Please find the table for the gerrits you provided:- <br>
</p>
%s
</body>
</html>
"""%(mft)
print "Emailing..."
email(email_body,"Manifest table","test#company.com")
if __name__ == '__main__':
main()
For making your table I suggest to use string.Template:
this is simple example:
from string import Template
a = Template("$name is my friend")
b=a.substitute(name="Sara")
print b
#output: Sara is my friend
So about a part of your code:
table_items = table_items + "<tr><td>%s</td><td>%s</td></tr>"%(project,branch)
you can do it better:
table_items += "<tr><td>%(p)s</td><td>%(b)s</td></tr>" % {'p':project,'b':branch}
or via string.Template:
table_items = Template("<tr><td>$p</td><td>$b</td></tr>")
table_items += table_items.substitute(p=project,b=branch)
We have a code which extract the service list from our tomcat server and insert it into a database. Basically, the code will receive a huge output ( 100+ results ) from a html result with the following structure:
<TABLE bgcolor=#dddddd border=1>
<TR>
<TD valign="top"><B>name</B></TD>
<TD>Loader</TD>
</TR>
<TR>
<TD valign="top"><B>enabled</B></TD>
<TD>true</TD>
</TR>
<TR>
<TD valign="top"><B>loadok</B></TD>
<TD>13</TD>
</TR>
</TABLE>
<TABLE bgcolor=#dddddd border=1>
<TR>
<TD valign="top"><B>name</B></TD>
<TD>tester</TD>
</TR>
<TR>
<TD valign="top"><B>enabled</B></TD>
<TD>false</TD>
</TR>
<TR>
<TD valign="top"><B>loadok</B></TD>
<TD>13</TD>
</TR>
</TABLE>
Following, the actual code ( which works )
#!/usr/bin/env python
import psycopg2
import urllib2
import base64
import sys
import re
import lxml.html as LH
con = None
try:
con = psycopg2.connect(database='xx', user='xx',password='xx',host='vxx')
cur = con.cursor()
qry ="select iservers.env,iservers.family,iservers.prefix,iservers.iserver,iservers.login,iservers.password,services.service," +\
"proxy_access.proxy_server,proxy_access.proxy_user,proxy_access.proxy_pass " +\
"from services,iservers,proxy_access where iservers.env='TEST' and services.id='2' "
cur.execute(qry)
data = cur.fetchall()
for result in data:
env = result[0]
family = result[1]
prefix = result[2]
iserver = result[3]
login = result[4]
password = result[5]
service = result[6]
proxyHost = result[7]
proxyUser = result[8]
proxyPass = result[9]
proxy_auth = "http://"+proxyUser+":"+proxyPass+"#"+proxyHost
proxy_handler = urllib2.ProxyHandler({"http": proxy_auth})
opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)
request = urllib2.Request("http://"+iserver+service)
base64string = base64.encodestring('%s:%s' % (login, password)).replace('\n', '')
request.add_header("Authorization", "Basic %s" % base64string)
response = urllib2.urlopen(request)
html = response.read()
###################### CHANGE THIS TO USE A HTML PARSER
regex = r"name</B></TD>\s<TD>(.*?)</TD>\s</TR>\s<TR>\s(.*)enabled</B></TD>\s<TD>(.*)</TD>"
for m in re.finditer(regex,html):
print "inserting\t"+iserver+"\t"+m.group(1)
cur.execute("INSERT INTO pereirtc.package_status (env,family,iserver,prefix,package,status) values (%s,%s,%s,%s,%s,%s)",(env,family,iserver,prefix,m.group(1),m.group(3)))
con.commit()
###################### END
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
After some help from Stack Overflow, I was advised to change the block on "change this ...." to libxml. So I got the following block to use:
doc = LH.fromstring(html)
tds = (td.text_content() for td in doc.xpath("//td"))
for td, val in zip(*[tds]*2):
if td in ("name","enabled"):
print (td,val)
With the example above, I have the result:
('name', 'Loader')
('enabled', 'true')
And what I want is, to insert the result using xpath to insert it into a database. Since I'm starting on python, I'm blocked on how I can do that with xpath/libxml.
I'm not sure if you meant the following simple operation, but splitting the result into two variables is achieved as follows:
doc = LH.fromstring(html)
tds = (td.text_content() for td in doc.xpath("//td"))
for td, val in zip(*[tds]*2):
if td == "name":
name = val
elif td == "enabled":
enabled = val
print name
print enabled
I'm guessing that:
blah = [('name', 'Loader'), ('enabled', 'true')]
blahd = dict(blah)
cursor.execute('insert into blah (name, enabled) values(%(name)s, %(enabled)s)', blahd)
Or, not using named values...:
cursor.execute('insert into blah (name, enabled) values(?, ?)', [i[1] for i in blah])