Problem when trying to run python script from VBA - python

I'm new on coding.. I'm trying to write my first script called from VBA and I always. The script works well itself, but now I want to call it from VBA passing two variables (the URL and file name).
I alway get error in the shell line.
I hope you can help me..
thanks
This is the URL containing the table to download: https://jde.erpref.com/?schema=920&table=F4311
#this is my VBA code:
Sub Dw_table()
Dim url As String
Dim file_name As String
Dim PythonExe, PythonScript As String
Dim objShell As Object
' Prompt the user to enter the URL and file name
url = InputBox("Enter the URL of the table:")
file_name = InputBox("Enter the file name:")
'paths for exe and script
PythonExe = """C:\Users\Mario Rdz\AppData\Local\Programs\Python\Python311\python.exe"""
PythonScript = "C:\Users\Mario Rdz\PycharmProjects\HelloWorld\JDEREF.py"
objShell.Run PythonExe & PythonScript & url & file_name
End Sub
this is my python code
from bs4 import BeautifulSoup
import requests
import openpyxl
import sys
# Passed arguments from excel VBA
url = sys.argv[1]
file_name = sys.argv[2]`
page = requests.get(url)
#Parse the HTML content of the webpage
soup = BeautifulSoup(page.content, "html.parser")
#Find the table with the ID "columnselectcollection"
table = soup.find(id="columnselectcollection")
#Create a new workbook and add a worksheet
your text`workbook = openpyxl.Workbook()
worksheet = workbook.active
#Create a new workbook and add a worksheet
workbook = openpyxl.Workbook()
worksheet = workbook.active
#Set the values for column headers
worksheet.cell(row=1, column=2).value = "Seq"
worksheet.cell(row=1, column=3).value = "Field"
worksheet.cell(row=1, column=4).value = "Description"
worksheet.cell(row=1, column=5).value = "Data type"
worksheet.cell(row=1, column=6).value = "Edit Type type"
worksheet.cell(row=1, column=7).value = "Lenght"
worksheet.cell(row=1, column=8).value = "Decimals"
#Iterate over the rows of the table and write the data to the worksheet
for row in table.find_all('tr'):
row_data = []
for cell in row.find_all('td'):
row_data.append(cell.text)
worksheet.append(row_data)
#delete row 2 which is blanks and delete unuseful column 9
worksheet.delete_cols(9)
worksheet.delete_rows(2)
#Save the workbook to an Excel file
workbook.save(f"{file_name}.xlsx")
I think the issue ius the way how I'm calling the python script or how I'm passing the URL and file name to the python script

Related

How to Stop Override data in Excel by Python

I am saving data in an excel file, but it overrides the data and previous data loss, whenever I run the program again. I want to save data under the previous data every time whenever I run the program. sorry for the whole code because I don't which part of the code I should share with you. help, please!
//Python Code
from time import time
from turtle import heading, title
import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font
from openpyxl.utils import get_column_letter
# links in array of cardano only
links = ["https://cardanoscan.io/pool/eff96bfccda465d5be2c42e97ab4c6013bd08b29bd8a41feafcd4713", "https://cardanoscan.io/pool/54ee46b05aac43c6f692963d731037b1747a4cebfc119ccd2c5ad78b", "https://cardanoscan.io/pool/c44a041de1e1e85d5f89a5afac6d3c304e411855b2418ae209178cdc", "https://cardanoscan.io/pool/1f79d3dd8366a9d04512e59e3cd65c1342eaa261b641ef93e5ac8f86",
"https://cardanoscan.io/pool/37776026d64eeb9fb5873caedc6e9c140f66c43ef6b3e396e061c891", "https://cardanoscan.io/pool/51897956cbe5c8f4751953c31ce85a1c60f5f27efee16397e6654947", "https://cardanoscan.io/pool/27ef7af15a7b854508385bf193acd73f7fb78b72ea6a99e8a413ca68", "https://cardanoscan.io/pool/b1b2d76b11afa2fbc6b5f89f078b47a9defa00707975f3fd4ebe1df2", "https://cardanoscan.io/pool/9390bd2c8d16935b3bdfeaae6301c203f67806511e492e3cf3dbfc69"]
print("Searching for Alerts!")
# loop to check alerts in website
wb = Workbook()
ws = wb.active
ws.title = "Links Alerts"
# Data Headings
headings = ['Branch Name', 'Branch Link', 'Threshold', 'Percentage', 'Status']
ws.append(headings)
# making bold headings
for col in range(1, 6):
ws[get_column_letter(col) + '1'].font = Font(bold=True)
# creating the main function to check alerts
def find_alerts():
for link in links: # searching link in lines one by one
# request to get link data in text form
html_text = requests.get(link).text
# BeautifulSoup fromating the data for us
soup = BeautifulSoup(html_text, "lxml")
soup.prettify
result = soup.find(
'div', class_='position-absolute font-weight-bold').text.replace(' ', '') # target the class where the data lies
if "0%" not in result: # condition for change
ws.append(["Cardano", link, "Saturation",
result, "Issue found"]) # creating row if the condition execute
print(
f"Issue found in link: {link} because of {result} saturation.")
else:
ws.append(["Cardano", link, "Saturation",
result, " No Issue found"]) # same thing as above
print("no Issue in this link!")
ws.insert_rows(11) # making space for new data
wb.save('Alert_Checking.xlsx') # saving file
if __name__ == '__main__':
while True:
find_alerts() # calling the function
time_wait = 60 # setting time
print(" ")
print(f"Wating for {time_wait} minutes to recheck again...")
print(" ")
input("Press Enter key to close the Tab!")
time.sleep(time_wait * 60)
You are creating a new workbook every time you run your script, so of course you won't retain data when running the script again. You can use a try ... except block to try and open the file, or create if it doesn't exist.
filename = "Alert_Checking.xlsx"
try:
# File already exists, load file
load_workbook(filename)
ws = wb["Links Alerts"]
except FileNotFoundError:
# File does not exist, create file
wb = Workbook()
ws = wb.active
ws.title = "Links Alerts"
# Data Headings
headings = ['Branch Name', 'Branch Link', 'Threshold', 'Percentage', 'Status']
ws.append(headings)
# making bold headings
for col in range(1, 6):
ws[get_column_letter(col) + '1'].font = Font(bold=True)

Formating of URL in webbrowser doesn't work

Chrome says it can not find the url.
Yet, When I run the program the URL prints out as:
'https://www.gettyimages.com/detail/photo/london-tower-bridge-river-thames-city-skyscrapers-royalty-free-image/860119662?adppopup=true'
If I replace the variable "url" with the actual url above in the webbrowser.open it finds the webpage perfectly.
Here is the actual code:
# Reading an excel file using Python
import xlrd
# Give the location of the file
loc = ('F:\\Documents\\Fun Stuff\\Other\\bridges.xlsx')
# To open Workbook
book = xlrd.open_workbook(loc)
sheet = book.sheet_by_index(0)
# input is requested and stored in a variable
row_text = input('Row Number = ')
# convert user input into an integer
row_number = int(row_text)
# For row “row_number” and column 2
cell_value = sheet.cell(row_number, 1)
url = str(cell_value)
url = url[5:]
#Verify url is extracted from Excel sheet
print(url)
# open-webpage
import webbrowser
#Path to webbrower
chrome_path = ('C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s')
# open-webpage
webbrowser.get(chrome_path).open(url, new=0)

Python Excel Program Update Every Run

I have this simple code and it creates a file "example.xlsx"
I only need the A1 Cell to have an output for the first run.
This is my initial code
from openpyxl import Workbook
import requests
workbook = Workbook()
sheet = workbook.active
success= "DONE"
sheet["A1"] = requests.get('http://ip.42.pl/raw').text
workbook.save(filename="example.xlsx")
print(success)
The first output is an excel file example.xlsx. I am required to update the same excel file every time we run the program. Example.
The 1st run has only A1 with the output from the website http://ip.42.pl/raw and the following will be input to A2, A3 and so on every run.
THANK YOU. I AM BEGINNER. PLEASE BEAR WITH ME
I modified the code, and now I think it does what you ask for:
from openpyxl import Workbook, load_workbook
import os
import requests
workbook = Workbook()
filename = "example.xlsx"
success = "DONE"
# First verifies if the file exists
if os.path.exists(filename):
workbook = load_workbook(filename, read_only=False)
sheet = workbook.active
counter = 1
keep_going = True
while keep_going:
cell_id = 'A' + str(counter)
if sheet[cell_id].value is None:
sheet[cell_id] = requests.get('http://ip.42.pl/raw').text
keep_going = False
else:
counter += 1
workbook.save(filename)
print(success)
else:
# If file does not exist, you have to create an empty file from excel first
print('Please create an empty file ' + filename + ' from excel, as it throws error when created from openpyxl')
Check the question xlsx and xlsm files return badzipfile: file is not a zip file for clarification about why you have to create an empty file from excel so openpyxl can work with it (line in the else: statement).
You could use sheet.max_row in openpyxl to get the length. Like so:
from openpyxl import Workbook
import requests
workbook = Workbook()
sheet = workbook.active
max_row = sheet.max_row
success= "DONE"
sheet.cell(row=max_row+1, column=1).value = requests.get('http://ip.42.pl/raw').text
# sheet["A1"] = requests.get('http://ip.42.pl/raw').text
workbook.save(filename="example.xlsx")
print(success)

Copy excel sheet from one worksheet to another in Python

All I want to do is copy a worksheet from an excel workbook to another excel workbook in Python.
I want to maintain all formatting (coloured cells, tables etc.)
I have a number of excel files and I want to copy the first sheet from all of them into one workbook. I also want to be able to update the main workbook if changes are made to any of the individual workbooks.
It's a code block that will run every few hours and update the master spreadsheet.
I've tried pandas, but it doesn't maintain formatting and tables.
I've tried openpyxl to no avail
I thought xlwings code below would work:
import xlwings as xw
wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
new_wb.sheets["Sheet1"] = sht
But I just get the error:
----> 4 new_wb.sheets["Sheet1"] = sht
AttributeError: __setitem__
"file1.xlsx" above is an example first excel file.
"Master Spreadsheet.xlsx" is my master spreadsheet with all individual files.
In the end I did this:
def copyExcelSheet(sheetName):
read_from = load_workbook(item)
#open(destination, 'wb').write(open(source, 'rb').read())
read_sheet = read_from.active
write_to = load_workbook("Master file.xlsx")
write_sheet = write_to[sheetName]
for row in read_sheet.rows:
for cell in row:
new_cell = write_sheet.cell(row=cell.row, column=cell.column,
value= cell.value)
write_sheet.column_dimensions[get_column_letter(cell.column)].width = read_sheet.column_dimensions[get_column_letter(cell.column)].width
if cell.has_style:
new_cell.font = copy(cell.font)
new_cell.border = copy(cell.border)
new_cell.fill = copy(cell.fill)
new_cell.number_format = copy(cell.number_format)
new_cell.protection = copy(cell.protection)
new_cell.alignment = copy(cell.alignment)
write_sheet.merge_cells('C8:G8')
write_sheet.merge_cells('K8:P8')
write_sheet.merge_cells('R8:S8')
write_sheet.add_table(newTable("table1","C10:G76","TableStyleLight8"))
write_sheet.add_table(newTable("table2","K10:P59","TableStyleLight9"))
write_to.save('Master file.xlsx')
read_from.close
With this to check if the sheet already exists:
#checks if sheet already exists and updates sheet if it does.
def checkExists(sheetName):
book = load_workbook("Master file.xlsx") # open an Excel file and return a workbook
if sheetName in book.sheetnames:
print ("Removing sheet",sheetName)
del book[sheetName]
else:
print ("No sheet ",sheetName," found, will create sheet")
book.create_sheet(sheetName)
book.save('Master file.xlsx')
with this to create new tables:
def newTable(tableName,ref,styleName):
tableName = tableName + ''.join(random.choices(string.ascii_uppercase + string.digits + string.ascii_lowercase, k=15))
tab = Table(displayName=tableName, ref=ref)
# Add a default style with striped rows and banded columns
tab.tableStyleInfo = TableStyleInfo(name=styleName, showFirstColumn=False,showLastColumn=False, showRowStripes=True, showColumnStripes=True)
return tab
Adapted from this solution, but note that in my (limited) testing (and as observed in the other Q&A), this does not support the After parameter of the Copy method, only Before. If you try to use After, it creates a new workbook instead.
import xlwings as xw
wb = xw.Book('individual_files\\file1.xlsx')
sht = wb.sheets[0]
new_wb = xw.Book('Master Spreadsheet.xlsx')
# copy this sheet into the new_wb *before* Sheet1:
sht.api.Copy(Before=new_wb.sheets['Sheet1'].api)
# now, remove Sheet1 from new_wb
new_wb.sheets['Sheet1'].delete()
This can be done using pywin32 directly. The Before or After parameter needs to be provided (see the api docs), and the parameter needs to be a worksheet <object>, not simply a worksheet Name or index value. So, for example, to add it to the end of an existing workbook:
def copy_sheet_within_excel_file(excel_filename, sheet_name_or_number_to_copy):
excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')
wb = excel_app.Workbooks.Open(excel_filename)
wb.Worksheets[sheet_name_or_number_to_copy].Copy(After=wb.Worksheets[wb.Worksheets.Count])
new_ws = wb.ActiveSheet
return new_ws
As most of my code runs on end-user machines, I don't like to make assumptions whether Excel is open or not so my code determines if Excel is already open (see GetActiveObject), as in:
try:
excel_app = win32com_client.GetActiveObject('Excel.Application')
except com_error:
excel_app = win32com_client.gencache.EnsureDispatch('Excel.Application')
And then I also check to see if the workbook is already loaded (see Workbook.FullName). Iterate through the Application.Workbooks testing the FullName to see if the file is already open. If so, grab that wb as your wb handle.
You might find this helpful for digging around the available Excel APIs directly from pywin32:
def show_python_interface_modules():
os.startfile(os.path.dirname(win32com_client.gencache.GetModuleForProgID('Excel.Application').__file__))

Insert hyperlink to a local folder in Excel with Python

The piece of code reads an Excel file. This excel file holds information such as customer job numbers, customer names, sites, works description ect..
What this code will do when completed (I hope) is read the last line of the worksheet (this is taken from a counter on the worksheet at cell 'P1'), create folders based on cell content, and create a hyperlink on the worksheet to open the lowest local folder that was created.
I have extracted the info I need from the worksheet to understand what folders need to be created, but I am not able to write a hyperlink to the cell on the row in column B.
#Insert Hyperlink to folder
def folder_hyperlink(last_row_position, destination):
cols = 'B'
rows = str(last_row_position)
position = cols + rows
final_position = "".join(position)
print final_position # This is just to check the value
# The statement below should insert hyperlink in eps.xlsm > worksheet jobnoeps at column B and last completed row.
ws.cell(final_position).hyperlink = destination
The complete code is below but here is the section that is meant to create the hyperlink. I have also tried the 'xlswriter' package with no joy. Searched the internet and the above snippet is the result of what I found.
Anyone know what I am doing wrong?
__author__ = 'Paul'
import os
import openpyxl
from openpyxl import load_workbook
import xlsxwriter
site_info_root = 'C:\\Users\\paul.EPSCONSTRUCTION\\PycharmProjects\\Excel_Jobs\\Site Information\\'
# This function returns the last row on eps.xlsm to be populated
def get_last_row(cell_ref = 'P1'): #P1 contains the count of the used rows
global wb
global ws
wb = load_workbook("eps.xlsm", data_only = True) #Workbook
ws = wb["jobnoeps"] #Worksheet
last_row = ws.cell(cell_ref).value #Value of P1 from that worksheet
return last_row
# This function will read the job number in format EPS-XXXX-YR
def read_last_row_jobno(last_row_position):
last_row_data = []
for cols in range(1, 5):
last_row_data += str(ws.cell(column = cols, row = last_row_position).value)
last_row_data_all = "".join(last_row_data)
return last_row_data_all
#This function will return the Customer
def read_last_row_cust(last_row_position):
cols = 5
customer_name = str(ws.cell(column = cols, row = last_row_position).value)
return customer_name
#This function will return the Site
def read_last_row_site(last_row_position):
cols = 6
site_name = str(ws.cell(column = cols, row = last_row_position).value)
return site_name
#This function will return the Job Discription
def read_last_row_disc(last_row_position):
cols = 7
site_disc = str(ws.cell(column = cols, row = last_row_position).value)
return site_disc
last_row = get_last_row()
job_no_details = read_last_row_jobno(last_row)
job_customer = read_last_row_cust(last_row)
job_site = read_last_row_site(last_row)
job_disc = read_last_row_disc(last_row)
cust_folder = job_customer
job_dir = job_no_details + "\\" + job_site + " - " + job_disc
#Insert Hyperlink to folder
def folder_hyperlink(last_row_position, destination):
cols = 'B'
rows = str(last_row_position)
position = cols + rows
final_position = "".join(position)
print final_position # This is just to check the value
# The statement below should insert hyperlink in eps.xlsm > worksheet jobnoeps at column B and last completed row.
ws.cell(final_position).hyperlink = destination
folder_location = site_info_root + job_customer + "\\" + job_dir
print folder_location # This is just to check the value
folder_hyperlink(last_row, folder_location)
Now my hyperlink function looks like this after trying xlsxwriter as advised.
##Insert Hyperlink to folder
def folder_hyperlink(last_row_position, destination):
import xlsxwriter
cols = 'B'
rows = str(last_row_position)
position = cols + rows
final_position = "".join(position)
print final_position # This is just to check the value
workbook = xlsxwriter.Workbook('eps.xlsx')
worksheet = workbook.add_worksheet('jobnoeps')
print worksheet
worksheet.write_url(final_position, 'folder_location')
workbook.close()
The function overwrites the exsisting eps.xlsx, creates a jobnoeps table and then inserts the hyperlink. I have played with the following lines but don't know how to get it to open the existing xlsx and existing jobnoeps tab and then enter the hyperlink.
workbook = xlsxwriter.Workbook('eps.xlsx')
worksheet = workbook.add_worksheet('jobnoeps')
worksheet.write_url(final_position, 'folder_location')
The XlsxWriter write_url() method allows you to link to folders or other workbooks and worksheets as well as internal links and links to web urls. For example:
import xlsxwriter
workbook = xlsxwriter.Workbook('links.xlsx')
worksheet = workbook.add_worksheet()
worksheet.set_column('A:A', 50)
# Link to a Folder.
worksheet.write_url('A1', r'external:C:\Temp')
# Link to a workbook.
worksheet.write_url('A3', r'external:C:\Temp\Book.xlsx')
# Link to a cell in a worksheet.
worksheet.write_url('A5', r'external:C:\Temp\Book.xlsx#Sheet1!C5')
workbook.close()
See the docs linked to above for more details.
Here is the code that did the trick:-
# Creates hyperlink in existing workbook...
def set_hyperlink():
from openpyxl import load_workbook
x = "hyperlink address"
wb = load_workbook("filename.xlsx")
ws = wb.get_sheet_by_name("sheet_name")
ws.cell(row = x?, column = y?).hyperlink = x
wb.save("filename.xlsx")
set_hyperlink()
Tried again with openpyxl as advised.

Categories