I'm generating a csv file (with thousands of rows) on my local PC. From a Google account, I would like to do a manual Google Sheets>Import to upload the file for my book club group. The data is collected from HTML tables on multiple pages, if that matters.
One of the fields is named "shelves" is essentially tags, and it contains a list of (name, url) tuples. I'd like to modify my Python program to make a list along the lines of
[=HYPERLINK(url, name), =HYPERLINK(url, name), ..., =HYPERLINK(url, name)]
but I can't find any syntax clues. I also tried
['=HYPERLINK("url", "name"), =HYPERLINK("url", "name")', '=HYPERLINK("url", "name"), =HYPERLINK("url", "name")', ...]
Can something like this via importing a CSV file from Google Sheets work or not, in Aug 2022?
Here's a sample CSV row:
,title,title_url,author,author_url,shelves,date_started,date_finished,member_name,member_url,date_added,group_activity,group_book_id_url'
'29,"Luck in the Shadows (Nightrunner, #1)",http://goodreads.com/book/show/74270.Luck_in_the_Shadows,"Flewelling, Lynn",http://goodreads.com/author/show/42110.Lynn_Flewelling,"[('http://goodreads.com/group/bookshelf/group?shelf=read', 'read'), ('http://goodreads.com/group/bookshelf/group?shelf=1-book-of-the-month', '1-book-of-the-month'), ('http://goodreads.com/group/bookshelf/group?shelf=char-royalty-nobility', 'char-royalty-nobi...'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-action-adventure', 'genre-action-adve...'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-epic', 'genre-epic'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-fantasy', 'genre-fantasy'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-romance', 'genre-romance'), ('http://goodreads.com/group/bookshelf/group?shelf=profession-mage-witch-wizard', 'profession-mage-w...'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-cross-dressing', 'theme-cross-dressing'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-nautical', 'theme-nautical'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-on-the-run', 'theme-on-the-run'), ('http://goodreads.com/group/bookshelf/group?shelf=time-historical', 'time-historical')]",1/1/2021,1/31/2021,Marianne ,http://goodreads.com/user/show/marianne,"group activity for 536628',http://goodreads.com/group/show_book/group?group_book_id=536628
So shelves is the field I'm working on. As you can see it has a long list (and edited for brevity):
[('http://goodreads.com/group/bookshelf/group?shelf=read', 'read'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-action-adventure', 'genre-action-adve...'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-epic', 'genre-epic'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-fantasy', 'genre-fantasy'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-romance', 'genre-romance'), ('http://goodreads.com/group/bookshelf/group?shelf=profession-mage-witch-wizard', 'profession-mage-w...'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-on-the-run', 'theme-on-the-run'), ('http://goodreads.com/group/bookshelf/group?shelf=time-historical', 'time-historical')]
I would like to have a csv-type file that can be manually imported into Google Sheets and have a single cell contain the shelves list in the following fashion:
`[=HYPERTEXT('http://goodreads.com/group/bookshelf/group?shelf=read', 'read'), =HYPERTEXT('http://goodreads.com/group/bookshelf/group?shelf=genre-action-adventure', 'genre-action-adve...')]
So that when it is uploaded to Google it displays similarly to an html table cell:
Before I go through a ton of iterations of that, I wanted to see if that would even work. All the research I've done has come up with mostly 2020 info about only being able to do this in the Google Apps environment, or to possibly write a function for the spreadsheet. I did sign up and try the Google Apps environment, but got stuck in setting up credentials.
If not, is there a best approach to somehow accomplish this?
If it is possible, I could use some help on the syntax. Thank you!
I believe your goal is as follows.
You want to upload CSV data of your local PC to your Google Drive.
Here, from your question, the uploading data is as follows.
[('http://goodreads.com/group/bookshelf/group?shelf=read', 'read'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-action-adventure', 'genre-action-adve...'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-epic', 'genre-epic'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-fantasy', 'genre-fantasy'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-romance', 'genre-romance'), ('http://goodreads.com/group/bookshelf/group?shelf=profession-mage-witch-wizard', 'profession-mage-w...'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-on-the-run', 'theme-on-the-run'), ('http://goodreads.com/group/bookshelf/group?shelf=time-historical', 'time-historical')]
You want to create a new Spreadsheet and put the formulas like =HYPERLINK("url", "name") to the column "A" of the new Spreadsheet.
You want to achieve this using a python script. And, when the data is uploaded, you don't want to authorize the scopes.
Unfortunately, when the data is uploaded to Google Drive, authorization is required to be used. So, in this answer, in order to achieve your goal, as a workaround, I used Web Apps as a wrapper API. When Web Apps is used, the authorization can be done when the Web Apps is deployed. By this, when the script accesses the Web Apps, the data can be uploaded without authorization. In this case, how about the following method?
Usage:
1. Create a Google Apps Script project.
In order to use Web Apps, please create a new Google Apps Script project. When you access https://script.google.com/home and create a new project. You can create a new Google Apps Script project.
2. Sample script.
Please copy and paste the following script to the script editor of the created Google Apps Script project.
function doPost(e) {
const data = JSON.parse(e.postData.contents);
const newSS = SpreadsheetApp.create("sample");
const formulas = data.map(([a, b]) => [`=HYPERLINK("${a}", "${b}")`]);
newSS.getSheets()[0].getRange(1, 1, formulas.length, 1).setFormulas(formulas);
return ContentService.createTextOutput(newSS.getUrl());
}
In this case, as a sample, a new Spreadsheet is created to the root folder.
If you want to achieve your goal without using =HYPERLINK(), please modify as follows.
From
const formulas = data.map(([a, b]) => [`=HYPERLINK("${a}", "${b}")`]);
newSS.getSheets()[0].getRange(1, 1, formulas.length, 1).setFormulas(formulas);
To
const rValues = data.map(([a, b]) => [SpreadsheetApp.newRichTextValue().setText(b).setLinkUrl(a).build()]);
newSS.getSheets()[0].getRange(1, 1, rValues.length).setRichTextValues(rValues);
3. Deploy Web Apps.
The detailed information can be seen at the official document.
Please set this using the new IDE of the script editor.
On the script editor, at the top right of the script editor, please click "click Deploy" -> "New deployment".
Please click "Select type" -> "Web App".
Please input the information about the Web App in the fields under "Deployment configuration".
Please select "Me" for "Execute as".
Please select "Anyone" for "Who has access".
Please click "Deploy" button.
Copy the URL of the Web App. It's like https://script.google.com/macros/s/###/exec.
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
4. Testing:
In order to test the above Web Apps, in this case, from your question, a python script and your showing data are used. The sample script is as follows. Before you use this, please set url.
import json
import requests
url = "https://script.google.com/macros/s/###/exec" # Please replace this with your Web Apps URL.
# This data is from your question.
data = [('http://goodreads.com/group/bookshelf/group?shelf=read', 'read'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-action-adventure', 'genre-action-adve...'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-epic', 'genre-epic'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-fantasy', 'genre-fantasy'), ('http://goodreads.com/group/bookshelf/group?shelf=genre-romance', 'genre-romance'), ('http://goodreads.com/group/bookshelf/group?shelf=profession-mage-witch-wizard', 'profession-mage-w...'), ('http://goodreads.com/group/bookshelf/group?shelf=theme-on-the-run', 'theme-on-the-run'), ('http://goodreads.com/group/bookshelf/group?shelf=time-historical', 'time-historical')]
res = requests.post(url, json.dumps(data))
print(res.text)
From your question, I understood that you have already had data in the above script. So, I used it.
When this script is run, your data is sent to Web Apps without the authorization. Because the authorization has already been done when Web Apps is deployed. The uploaded data is parsed and set the values as the formula. And, the URL of the created new Spreadsheet is returned.
Note:
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Google's Import function cannot automatically translate a field containing a list of URLs into a single field as a list of Hyperlinks, regardless of the URL format used in the CSV field.
The user must write a Google Sheet Extension using Extensions > Apps Scripts in the relevant Sheet. Thanks to Tanaike's Answer that supplies comprehensive directions.
The user can then copy that script to their other Google Sheets that Import similarly formatted files.
I'm trying to use Facebook's Graph API to get all the restaurants within a certain location. I'm doing this on Python and my url is
url ="https://graph.facebook.com/search?type=place¢er=14.6091,121.0223,50000&categories=[\"FOOD_BEVERAGE\"]&fields=name,location,category,fan_count,rating_count,overall_star_rating&limit=100&access_token=" + access
However, this is the error message I get.
{
"error": {
"message": "(#100) For field 'placesearch': param categories must be an array.",
"code": 100,
"type": "OAuthException",
"fbtrace_id": "EGQ8YdwnzUT"
}
}
But when I paste the URL on the Graph explorer (linked below), it works. I can't do this exhaustively on the explorer because I need to collect restaurant data from all the next pages. Can someone help me explain why this is happening and how to fix it so that I can access it through Python?
Example Link
You did not specify an API version, so this will fall back to the lowest version your app can use.
I can reproduce the error for API versions <= v2.8 in Graph API Explorer - for v2.9 and above it works.
So use https://graph.facebook.com/v2.9/search?… (at least, or a higher version, up to you.)
I am making a data-plotting tool using google app engine and google docs/gdata and have run into a python/js/html communication issue.
I want a very simple layout for the webpage -- just a series of dropdown menu sections and then the final graphs. My current dilemma involves the dropdown menus.
There are total of 4 dropdown menus, and the fields of each one depends on the previous selection. I have found JS/HTML code that has all of the needed logic, but it assumes that you have pre-loaded all of the selection fields. Due to the scale of the project, it is impossible to load everything on start-up, and the data is dynamic/changing, so I can't just declare static files with the menu selection data contained.
Currently, I have methods to get all of the menu selections/data I need from google docs (using gdata). Ideally, I would like to just call each one in series (html selection1 -> python method1 to get next selection set -> html selection2 -> python method2 to get next selection set-> etc) but from what I can gather it seems this is not possible (return to python, ie 'post', without reloading the entire page).
So, is there a way to access python variables/methods in a google-app-engine JS code AFTER the initial template render or without 'posting'? Or, more open-endedly, if anyone has insight/suggestions/ideas I'd appreciate it.
Thanks
Two step process:
Create some server side code to return your data as JSON - the defacto method of transferring data on the web.
In your javascript code, call your server (from step 1) and then parse the result. Use the result to populate your dropdown.
The good news is that Google already provides json as an alternate format for their gdata APIs. See this link for a primer on how to use gdata and return JSON.
For the second part, almost all javascript client side libraries (and you really should be using one) provide an easy way to request data using ajax. As this is a common task, there are plenty of questions on StackOverflow on this - this one in particular has an example that shows you how to populate a dropdown using jquery and ajax.
Assuming you can use javascript and replicate whatever functionality your Python code is providing, the above will work for you. If you have some specific logic that you don't want to transfer to the client side, then your Python code will have to return json (in effect, you would be acting like the gdata api for your javascript code).
Since you didn't highlight which Python framework you are using - here is an example using flask, a simple framework for Python web development:
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/the-question')
def the_answer():
return jsonify(answer=42)
A more comprehensive example is available in the documentation under AJAX with jQuery.
If you are using webapp2, Google provides excellent documentation to do the same thing.
I wonder if it's possible to create and delete events with Google API in a secondary calendar. I know well how to do it in main calendar so I only ask, how to change calendar_service to read and write to other calendar.
I've tried loging with secondary calendar email, but that's not possible with BadAuthentication Error. The URL was surely correct, becouse it was read by API.
Waiting for your help.
A'm answering my own question so I can finally accept this one. The problem has been solved some time ago.
The most important answer is in this documentation.
Each query can be run with uri as argument. For example "InsertEvent(event, uri)". Uri can be set manually (from google calendar settings) or automatically, as written in post below. Note, that CalendarEventQuery takes only username, not the whole url.
The construction of both goes this way:
user = "abcd1234#group.calendar.google.com"
uri = "http://www.google.com/calendar/feeds/{{ user }}/private/full-noattendees"
What's useful, is that you can run queries with different uri and add/delete events to many different calendars in one script.
Hope someone finds it helpful.
I got the same issue but I found this solution (I do not remember where)
This solution is to extract the secondary calendar user from its src url provided by google
This is probably not the better one but it's a working one
Note:the code is extracted from a real project [some part has been removed] and must be adapted to your particular case and is provide as sample just to have a support for explaination (It will not work as is)
# 1 - Connect using the main user email address in a classical way
cal_client = gdata.calendar.service.CalendarService()
# insert here after connection stuff
# 2 - For each existing calendars
feed = cal_client.GetAllCalendarsFeed():
# a loop the find the calendar by it's title (cal_title)
for a_calendar in feed.entry:
if cal_title in a_calendar.title.text:
cal_user = a_calendar.content.src.split('/')[5].replace('%40','#')
# If you print a_calendar.content.src.split you will see that the url
# contains an email like definition. This is the one to used to work
# with the calendar
Then you just have to replace the default user by the cal_user in the api to work on the secondary calendar.
Replace call is required because google api function are doing internal conversion on special characters like '%'
I hope this will help you.