Add link to text within cell, not entire cell - python

Using Openpyxl, is there a way to create a link within a cell?
I tried:
worksheet['A1'].hyperlink = 'http://mypage.com'
However, this sets the entire cell of 'A1' to be a link. I would like it to set the text within the cell to a link so that it looks like: My page in cell A1.

You can try something like this:
wb = load_workbook("my_book.xlsx")
worksheet1 = wb.active()
cell_value = '=HYPERLINK("http://mypage.com", "My Page")'
worksheet1.cell(row=1, column=1, value=cell_value)
The important part of my example is that you can just set the value of the cell to excel's hyperlink function as a string. The first parameter is the link and the second parameter is the text to display in the cell.

Related

Column level adjustments in python-docx

I am trying to adjust the text on a per column basis in a docx table. I have tried
for row in doc.tables[2].column_cells(4):
font = run.font
font.size = Pt(8)
I don't get an error with the above code, but I also am not seeing any changes to the cell texts in that column
Make sure you are accessing the correct table: The code you provided is accessing the third table in the document (index 2) and the fourth column (index 3) of that table. Make sure that this is the table you want to make changes to, and that you are referencing the correct column.
Check the scope of the loop: Ensure that the loop is looping through the cells of the column correctly.
Use the .text attribute: the font attribute only affects the font of the text, not the text itself. You can use the .text attribute to change the text.
Apply the changes to the runs within the cells: Instead of changing the font of the whole cell, you should change the font of the runs within the cell. Each cell has a .paragraphs attribute that contains a list of the paragraphs in that cell, and each paragraph has a .runs attribute that contains a list of the runs of text within that paragraph.
for row in doc.tables[2].column_cells(3):
for paragraph in row.paragraphs:
for run in paragraph.runs:
run.font.size = Pt(8)
Save the changes: Remember to save the changes to the docx file after you have made the changes.
doc.save("updated_table.docx")

how to retrieve hyperlinks in spreadsheet cells using gspread?

I am not able to retrieve hyperlinks in google spreadsheet cells using gspread. I am always returned the text of the cell and not the hyperlink itself.
I have attempted
worksheet.cell(i, j, value_render_option="FORMULA")
with all the three possible options for value_render_option and none of them works.
I have seen some old answers here about using input_value, that unfortunately is not supported anymore
If your cell content is something like
=HYPERLINK("http://www.wikipedia.de","wikipedia")
try
cell = worksheet.cell(i, j, value_render_option='FORMULA').value

How to wrap cell text in tables via docx library or xml?

I have been using python docx library and oxml to automate some changes to my tables in my word document. Unfortunately, no matter what I do, I cannot wrap the text in the table cells.
I managed to successfully manipulate 'autofit' and 'fit-text' properties of my table, but non of them contribute to the wrapping of the text in the cells. I can see that there is a "w:noWrap" in the xml version of my word document and no matter what I do I cannot manipulate and remove it. I believe it is responsible for the word wrapping in my table.
for example in this case I am adding a table. I can fit text in cell and set autofit to 'true' but cannot for life of me wrap the text:
from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
doc = Document()
table = doc.add_table(5,5)
table.autofit = True # Does Autofit but not wrapping
tc = table.cell(0,0)._tc # As a test, fit text to cell 0,0
tcPr = tc.get_or_add_tcPr()
tcFitText = OxmlElement('w:tcFitText')
tcFitText.set(qn('w:val'),"true")
tcPr.append(tcFitText) #Does fitting but no wrapping
doc.save('demo.docx')
I would appreciate any help or hints.
The <w:noWrap> element appears to be a child of <w:tcPr>, the element that controls table cell properties.
You should be able to access it from the table cell element using XPath:
tc = table.cell(0, 0)._tc
noWraps = tc.xpath(".//w:noWrap")
The noWraps variable here will then be a list containing zero or more <w:noWrap> elements, in your case probably one.
Deleting it is probably the simplest approach, which you can accomplish like this:
if noWraps: # ---skip following code if list is empty---
noWrap = noWraps[0]
noWrap.getparent().remove(noWrap)
You can also take the approach of setting the value of the w:val attribute of the w:noWrap element, but then you have to get into specifying the Clark name of the attribute namespace, which adds some extra fuss and doesn't really produce a different outcome unless for some reason you want to keep that element around.

How to control table and picture position while using python-docx to generate MS-word

I want to put my picture and table(only 1 cell) like below:
Click here to see picture
I have to use such table because python-docx can't handle text-box yet. Basically I need to put my table beside my picture, not below or upper. I find that paragraph.run has add_picture() method to add picture at the end of paragraph, but not add_table() method to add one more table. Anyone know how to achieve this
i have tried so many ways to put a picture into a table ,that is what i do deal with my problem, you may find something you can use
from docx import Document
document = Document
table = document.add_table(rows=2, cols=3)
# set the whole table in the center position
table.alignment = WD_TABLE_ALIGNMENT.CENTER
row_cell = table.add_row().cells
# choice one row
**row_pic = row_cell[0]**
# clear blank area
**row_pic._tc.clear_content()**
# use paragraph function
**pic_run = row_pic.add_paragraph().add_run()**
# insert a picture path as a str into a cell from a table
**pic_run.add_picture('./picture/{}'.format("picture_name.jpg"), width=Inches(5))**

Taking CSV Field and Extracting Links to Separate Python-DocX Paragraphs

I'm working on a Python project that takes as CSV output file and re-formats the data and puts it into a Word Document using Python-DocX. Everything so far works great, but working with multiple hyperlinks in the same field causes all links to point to just the first link of the set.
Currently this is the code that is causing the issue:
p7 = document.add_paragraph()
hyperlink = add_hyperlink(p7, row['See Also'], str(row['See Also']))
As you can see the blank paragraph is initialised and then the hyperlink is assigned to it. row['See Also'] is the row that contains the links I need to work with. Some entries contain a single link and some contain a lot.
This (https://github.com/python-openxml/python-docx/issues/74) is the function that adds the hyperlink as per the documented method for Python-Docx:
def add_hyperlink(paragraph, url, text):
# This gets access to the document.xml.rels file and gets a new relation id value
part = paragraph.part
r_id = part.relate_to(
url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK,
is_external=True
)
# Create the w:hyperlink tag and add needed values
hyperlink = docx.oxml.shared.OxmlElement('w:hyperlink')
hyperlink.set(docx.oxml.shared.qn('r:id'), r_id, )
# Create a w:r element
new_run = docx.oxml.shared.OxmlElement('w:r')
# Create a new w:rPr element
rPr = docx.oxml.shared.OxmlElement('w:rPr')
# Join all the xml elements together add add the required text to the w:r element
new_run.append(rPr)
new_run.text = text
hyperlink.append(new_run)
paragraph._p.append(hyperlink)
return hyperlink
The way I thought to do it was to use a for loop to iterate through each hyperlink in the field and assign them to a paragraph each, that way the hyperlinks should work just fine. I tried the following but this just creates 1000's of links which do not work right.
for x in row['See Also']:
p = document.add_paragraph()
hyperlink = add_hyperlink(p, row['See Also'], row['See Also'])
I'm currently testing with a very small CSV file with just two sets of data as follows:
https://www.openssl.org/blog/blog/2016/08/24/sweet32/
This of course causes no issue and the hyperlink works as expected, however the following causes all links to point to the first address.
https://downloads.avaya.com/elmodocs2/security/ASA-2006-217.htm
http://www.kb.cert.org/vuls/id/JARL-5ZQR4D
http://www-01.ibm.com/support/docview.wss?uid=isg1IY55949
http://www-01.ibm.com/support/docview.wss?uid=isg1IY55950
http://www-01.ibm.com/support/docview.wss?uid=isg1IY62006
http://www.juniper.net/support/security/alerts/niscc-236929.txt
http://technet.microsoft.com/en-us/security/bulletin/ms05-019
http://technet.microsoft.com/en-us/security/bulletin/ms06-064
http://www.kb.cert.org/vuls/id/JARL-5YGQ9G
http://www.kb.cert.org/vuls/id/JARL-5ZQR7H
http://www.kb.cert.org/vuls/id/JARL-5YGQAJ
http://www.nessus.org/u?cf64c2ca
https://isc.sans.edu/diary.html?date=2004-04-20
The fix is probably quite straight forward, any help with this issue would be appreciated.
You haven't provided enough of the context code to show the specifics, but I suspect your problem is in the line:
for x in row['See Also']:
If you run:
for x in row['See Also']:
print x
I think you'll get:
h
t
t
p
s
:
...
As you can see, using a string value as the iterable in a for loop iterates the characters of the string.
What I think you need instead is something like:
for row in csv_rows:
p = document.add_paragraph()
hyperlink = add_hyperlink(p, row['See Also'], row['See Also'])
Figured the issue out and the following code solves the problem:
for row in csv_rows:
links = row['See Also'].split("\n")
for item in links:
p = document.add_paragraph()
hyperlink = add_hyperlink(p, item, item)
This splits each line of the 'See Also' row into a list and then this list is iterated through with each item being turned into a hyperlink.

Categories