Scraping data from url or websites - html
I'm new to Swift and I want to scrape some data from a website page. I get HTML from URL by using this code:
import swiftsoupe
import foundation
let url = URL(string: "https://www.example.com/")!
let html = try! String(contentsOf: url, encoding: String.Encoding.ascii)
do{
let document:Document = try (SwiftSoup.parse(html))
var script : [Element] = try document.select("script").array()
print(script[16])
}catch{
Swift.print("error saeed sorry")
}
print("done ! . . . ")
Then I get some data that I want in the script[16].
But when I want to get my data in this element there are no tags in it. It just like that in script[16]:
<script:
1. "locationBySearchTerm({\"search\":\"toronto\"})":{"__typename":"Location","countryCode":null,"displayName":"toronto","latitude":43.6534817,"longitude":-79.3839347,"regionCode":null,"stations({\"fuel\":1,\"maxAge\":0})":{"__typename":"StationResults","count":467,"cursor":{"__typename":"Cursor","next":"20"},"results":[{"__ref":"Station:4441"},{"__ref":"Station:69012"},{"__ref":"Station:65049"},{"__ref":"Station:65046"},{"__ref":"Station:26812"},{"__ref":"Station:12937"},{"__ref":"Station:205958"},{"__ref":"Station:64923"},{"__ref":"Station:65037"},{"__ref":"Station:65043"},{"__ref":"Station:65038"},{"__ref":"Station:40578"},{"__ref":"Station:22202"},{"__ref":"Station:22193"},{"__ref":"Station:25473"},{"__ref":"Station:87592"},{"__ref":"Station:6912"},{"__ref":"Station:64935"},{"__ref":"Station:85529"},{"__ref":"Station:65039"}]},"trends":[{"__typename":"Trend","areaName":"Toronto","country":"CA","today":152.1,"todayLow":135.9,"trend":1},{"__typename":"Trend","areaName":"Ontario","country":"CA","today":149.8,"todayLow":112.9,"trend":1},{"__typename":"Trend","areaName":"Canada","country":"CA","today":151,"todayLow":0,"trend":0}]}},"GtmConfig:GTM-N3CG6XK":{"__typename":"GtmConfig","id":"GTM-N3CG6XK"},"Offer:H44441-176-199-209-220-HcLI1qvrxBR2x2SXbzncb4h":{"__typename":"Offer","discounts":[{"__typename":"Discount","grades":["regular_gas"],"highlight":"Deal
Alert: Save 176¢ per
gallon","pwgbDiscount":"1.76","receiptDiscount":null},{"__typename":"Discount","grades":["midgrade_gas"],"highlight":"Deal
Alert: Save 199¢ per
gallon","pwgbDiscount":"1.99","receiptDiscount":null},{"__typename":"Discount","grades":["premium_gas"],"highlight":"Deal
Alert: Save 209¢ per
gallon","pwgbDiscount":"2.09","receiptDiscount":null},{"__typename":"Discount","grades":["diesel"],"highlight":"Deal
Alert: Save 220¢ per
gallon","pwgbDiscount":"2.20","receiptDiscount":null}],"highlight":"Deal
Alert: Save up to 220¢ per
gallon","id":"H44441-176-199-209-220-HcLI1qvrxBR2x2SXbzncb4h","types":["exampledy"],"use":["strike","sort"]},"Station:4441":{"__typename":"Station","address":{"__typename":"Address","country":"CA","line1":"117
Jarvis St","line2":"","locality":"Toronto","postalCode":"M5C
2H6","region":"ON"},"badges":[],"brandings":[{"__typename":"Branding","brand_id":"100","branding_type":"fuel"}],"brands":[{"__typename":"Brand","brand_id":"100","image_url":"https://images.gasbuddy.io/b/100.png","name":"Petro-Canada"}],"emergency_status":null,"enterprise":false,"fuels":["regular_gas","midgrade_gas","premium_gas","diesel"],"id":"4441","name":"Petro-Canada","offers":[{"__ref":"Offer:H44441-176-199-209-220-HcLI1qvrxBR2x2SXbzncb4h"}],"pay_status":null,"prices":[{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:10.327Z","price":154.9},"discount":0,"fuel_product":"regular_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:10.389Z","price":174.9},"discount":0,"fuel_product":"midgrade_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:10.420Z","price":183.9},"discount":0,"fuel_product":"premium_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:10.452Z","price":192.9},"discount":0,"fuel_product":"diesel"}],"priceUnit":"cents_per_liter","ratings_count":219,"star_rating":3.2},"Offer:H469012-176-197-206-226-H4alyPcKC2CExnuDI7QVmlP":{"__typename":"Offer","discounts":[{"__typename":"Discount","grades":["regular_gas"],"highlight":"Deal
Alert: Save 176¢ per
gallon","pwgbDiscount":"1.76","receiptDiscount":null},{"__typename":"Discount","grades":["midgrade_gas"],"highlight":"Deal
Alert: Save 197¢ per
gallon","pwgbDiscount":"1.97","receiptDiscount":null},{"__typename":"Discount","grades":["premium_gas"],"highlight":"Deal
Alert: Save 206¢ per
gallon","pwgbDiscount":"2.06","receiptDiscount":null},{"__typename":"Discount","grades":["diesel"],"highlight":"Deal
Alert: Save 226¢ per
gallon","pwgbDiscount":"2.26","receiptDiscount":null}],"highlight":"Deal
Alert: Save up to 226¢ per
gallon","id":"H469012-176-197-206-226-H4alyPcKC2CExnuDI7QVmlP","types":["gasbuddy"],"use":["strike","sort"]},"Station:69012":{"__typename":"Station","address":{"__typename":"Address","country":"CA","line1":"55
Spadina Ave","line2":"","locality":"Toronto","postalCode":"M5V
2J2","region":"ON"},"badges":[],"brandings":[{"__typename":"Branding","brand_id":"100","branding_type":"fuel"}],"brands":[{"__typename":"Brand","brand_id":"100","image_url":"https://images.gasbuddy.io/b/100.png","name":"Petro-Canada"}],"emergency_status":null,"enterprise":false,"fuels":["regular_gas","midgrade_gas","premium_gas","diesel"],"id":"69012","name":"Petro-Canada","offers":[{"__ref":"Offer:H469012-176-197-206-226-H4alyPcKC2CExnuDI7QVmlP"}],"pay_status":null,"prices":[{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:25.910Z","price":154.9},"discount":0,"fuel_product":"regular_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:25.923Z","price":172.9},"discount":0,"fuel_product":"midgrade_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:25.923Z","price":180.9},"discount":0,"fuel_product":"premium_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:25.939Z","price":198.9},"discount":0,"fuel_product":"diesel"}],"priceUnit":"cents_per_liter","ratings_count":181,"star_rating":3.7},"Offer:H465049-176-197-208-He0ySTOwrMLPd65PIOaE2hi":{"__typename":"Offer","discounts":[{"__typename":"Discount","grades":["regular_gas"],"highlight":"Deal
Alert: Save 176¢ per
gallon","pwgbDiscount":"1.76","receiptDiscount":null},{"__typename":"Discount","grades":["midgrade_gas"],"highlight":"Deal
Alert: Save 197¢ per
gallon","pwgbDiscount":"1.97","receiptDiscount":null},{"__typename":"Discount","grades":["premium_gas"],"highlight":"Deal
Alert: Save 208¢ per
gallon","pwgbDiscount":"2.08","receiptDiscount":null}],"highlight":"Deal
Alert: Save up to 208¢ per
gallon","id":"H465049-176-197-208-He0ySTOwrMLPd65PIOaE2hi","types":["gasbuddy"],"use":["strike","sort"]},"Station:65049":{"__typename":"Station","address":{"__typename":"Address","country":"CA","line1":"38
Spadina Ave","line2":"","locality":"Toronto","postalCode":"M5V
2H8","region":"ON"},"badges":[],"brandings":[{"__typename":"Branding","brand_id":"122","branding_type":"fuel"}],"brands":[{"__typename":"Brand","brand_id":"122","image_url":"https://images.gasbuddy.io/b/122.png","name":"Shell"}],"emergency_status":null,"enterprise":false,"fuels":["regular_gas","midgrade_gas","premium_gas"],"id":"65049","name":"Shell","offers":[{"__ref":"Offer:H465049-176-197-208-He0ySTOwrMLPd65PIOaE2hi"}],"pay_status":null,"prices":[{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:43.788Z","price":154.9},"discount":0,"fuel_product":"regular_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:43.829Z","price":172.9},"discount":0,"fuel_product":"midgrade_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:26:43.860Z","price":182.9},"discount":0,"fuel_product":"premium_gas"}],"priceUnit":"cents_per_liter","ratings_count":119,"star_rating":3.5},"Offer:H465046-176-199-209-220-H8renFkEWrviyInLZz8jnjs":{"__typename":"Offer","discounts":[{"__typename":"Discount","grades":["regular_gas"],"highlight":"Deal
Alert: Save 176¢ per
gallon","pwgbDiscount":"1.76","receiptDiscount":null},{"__typename":"Discount","grades":["midgrade_gas"],"highlight":"Deal
Alert: Save 199¢ per
gallon","pwgbDiscount":"1.99","receiptDiscount":null},{"__typename":"Discount","grades":["premium_gas"],"highlight":"Deal
Alert: Save 209¢ per
gallon","pwgbDiscount":"2.09","receiptDiscount":null},{"__typename":"Discount","grades":["diesel"],"highlight":"Deal
Alert: Save 220¢ per
gallon","pwgbDiscount":"2.20","receiptDiscount":null}],"highlight":"Deal
Alert: Save up to 220¢ per
gallon","id":"H465046-176-199-209-220-H8renFkEWrviyInLZz8jnjs","types":["gasbuddy"],"use":["strike","sort"]},"Station:65046":{"__typename":"Station","address":{"__typename":"Address","country":"CA","line1":"505
Jarvis St","line2":"","locality":"Toronto","postalCode":"M4Y
2H7","region":"ON"},"badges":[],"brandings":[{"__typename":"Branding","brand_id":"100","branding_type":"fuel"}],"brands":[{"__typename":"Brand","brand_id":"100","image_url":"https://images.gasbuddy.io/b/100.png","name":"Petro-Canada"}],"emergency_status":null,"enterprise":false,"fuels":["regular_gas","midgrade_gas","premium_gas","diesel"],"id":"65046","name":"Petro-Canada","offers":[{"__ref":"Offer:H465046-176-199-209-220-H8renFkEWrviyInLZz8jnjs"}],"pay_status":null,"prices":[{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:46.158Z","price":154.9},"discount":0,"fuel_product":"regular_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:46.189Z","price":174.9},"discount":0,"fuel_product":"midgrade_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:46.205Z","price":183.9},"discount":0,"fuel_product":"premium_gas"},{"__typename":"PriceReport","cash":null,"credit":{"__typename":"FuelPrice","nickname":"Georgrpg2004i","posted_time":"2023-01-23T21:27:46.221Z","price":192.9},"discount":0,"fuel_product":"diesel"}],"priceUnit":"cents_per_liter","ratings_count":196,"star_rating":3.8},"Offer:H426812-176-200-214-Hf26VTm7r4E1eI9Valb5Izx":{"__typename":"Offer","discounts":[{"__typename":"Discount","grades":["regular_gas]}
<script>
How can I get all names and ides and prices in it?
Or am I going the wrong way?
Related
How to access the tweepy entities expanded_url and why some are not available as object properties
I'm trying to get my head around tweepy and extracting data about followers in particular. I'm authenticated, queried twitter for details of my own followers and can print out details about them using Followers = AboutMe.followers for follows in Followers(): print(follows.id, "is user ID for ", follows.screen_name, " from ", follows.location, follows.url) When I execute that I get urls like https://t.co/[uniquestring] instead of FQDMs which I was hoping for There is a property/entity called expanded_url but its not accessible as a object property. Why is that? and how do I access it if its embedded in lower levels of json entities I provide a sample of the output if I print(follows.entities) {'url': {'urls': [{'url': 'https://t.co/[string]', 'expanded_url': 'http://www.fqdm', 'display_url': 'domain.tld', 'indices': [0, 23]}]}, 'description': {'urls': []}}
As per the documentation and the output of print(follows.entities) the following code answers your question to get FQDN for followers: Followers = AboutMe.followers for follows in Followers(): print(follows.id, "is user ID for ", follows.screen_name, " from ", follows.location, follows.entities.url.urls[0].expanded_url) You might also want to handle the case when user has no url.
How to order a json file list?
My goal is to get specific data on many profiles on khanacademy by using their API. My problem is: in their API, json files have different list orders. It can vary from one to another. Here is my code: from urllib.request import urlopen import json # here is a list with two json file links: profiles=['https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959','https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959'] # for each json file, take some specific data out for profile in profiles: print(profile) with urlopen(profile) as response: source = response.read() data = json.loads(source) votes = data[1]['renderData']['discussionData']['statistics']['votes'] print(votes) I expected something like this: https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 100 https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 41 Instead I got an error: https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 100 https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 Traceback (most recent call last): File "bitch.py", line 12, in <module> votes = data[1]['renderData']['discussionData']['statistics']['votes'] KeyError: 'discussionData' As we can see: This link A is working fine: https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 But this link B is not working: https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959 And that's because in this json file. The list is not in the same order as it is in the A link. My question is: Why? And how can I write my script to get into account these variation of orders? There is probably something to do with .sort(). But I am missing something. Maybe I should also precise that I am using python 3.7.2. Link A: desired data (yellow) is in the second item of the list (blue): Link B: desired data (yellow) is in the third item of the list (blue):
You could use an if to test if votes in current index dictionary import requests urls = ['https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959', 'https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959'] for url in urls: r = requests.get(url).json() result = [item['renderData']['discussionData']['statistics']['votes'] for item in r if 'votes' in str(item)] print(result)
Catching exceptions in python doesn't take much overhead unlike other languages so I would recommend the "better ask forgiveness then permission" solution. This will be slightly faster than searching through a str for the word votes as it will fail instantly if the key is invalid. import requests urls = ['https://www.khanacademy.org/api/internal/user/kaid_329989584305166460858587/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959', 'https://www.khanacademy.org/api/internal/user/kaid_901866966302088310331512/profile/widgets?lang=en&_=190424-1429-bcf153233dc9_1556201931959'] for url in urls: response = requests.get(url).json() result = [] for item in response: try: result.append(item['renderData']['discussionData']['statistics']['votes']) except KeyError: pass # Could not find votes print(result)
A python client to ContextualWeb News API using RapidAPI
I am trying to consume ContextualWeb News API. The endpoint is described here: https://rapidapi.com/contextualwebsearch/api/web-search Here is the request snippet in Python as described in RapidAPI: response = unirest.get("https://contextualwebsearch-websearch-v1.p.rapidapi.com/api/Search/NewsSearchAPI?autoCorrect=true&pageNumber=1&pageSize=10&q=Taylor+Swift&safeSearch=false", headers={ "X-RapidAPI-Host": "contextualwebsearch-websearch-v1.p.rapidapi.com", "X-RapidAPI-Key": "XXXXXX" } ) How do I send the request and parse the response? Can you provide a complete code example for the News API?
use the python version 3.X for below code.Below is the complete example example where I am passing string Taylor Swift and parsing response...Let me know if you stuck anywhere import requests # install from: http://docs.python-requests.org/en/master/ # Replace the following string value with your valid X-RapidAPI-Key. Your_X_RapidAPI_Key = "XXXXXXXXXXXXXXXXXXX"; # The query parameters: (update according to your search query) q = "Taylor%20Swift" # the search query pageNumber = 1 # the number of requested page pageSize = 10 # the size of a page autoCorrect = True # autoCorrectspelling safeSearch = False # filter results for adult content response = requests.get( "https://contextualwebsearch-websearch-v1.p.rapidapi.com/api/Search/NewsSearchAPI?q={}&pageNumber={}&pageSize={}&autocorrect={}&safeSearch={}".format( q, pageNumber, pageSize, autoCorrect, safeSearch), headers={ "X-RapidAPI-Key": Your_X_RapidAPI_Key } ).json() # Get the numer of items returned totalCount = response["totalCount"]; # Get the list of most frequent searches related to the input search query relatedSearch = response["relatedSearch"] # Go over each resulting item for webPage in response["value"]: # Get the web page metadata url = webPage["url"] title = webPage["title"] description = webPage["description"] keywords = webPage["keywords"] provider = webPage["provider"]["name"] datePublished = webPage["datePublished"] # Get the web page image (if exists) imageUrl = webPage["image"]["url"] imageHeight = webPage["image"]["height"] imageWidth = webPage["image"]["width"] thumbnail = webPage["image"]["thumbnail"] thumbnailHeight = webPage["image"]["thumbna`enter code here`ilHeight"] # An example: Output the webpage url, title and published date: print("Url: %s. Title: %s. Published Date:%s." % (url, title, datePublished))
Node.js JSON extract certain data
I'm trying to get certain data from a json link: bittrex.com/api/v1.1/public/getticker?market=BTC-DRS in my node IRC bot using: https://www.npmjs.org/package/node.bittrex.api Part of the code: var url = ('https://bittrex.com/api/v1.1/public/getticker?market=BTC-DRS'); bittrex.options({ 'apikey' : settings.ticker.apikey, 'apisecret' : settings.ticker.secretkey, 'stream' : false, 'verbose' : false, 'cleartext' : true, }); case 'ticker': var user = from.toLowerCase(); bittrex.sendCustomRequest(url, function(ticker, err) { if(err) { winston.error('Error in !ticker command.', err); client.say(channel, settings.messages.error.expand({name: from})); return; } winston.info('Fetched Price From BitTrex', ticker); client.say(channel, settings.messages.ticker.expand({name: user, price: ticker})); }); break; It works but outputs in IRC [1:21am] <nrpatten> !ticker [1:21am] <DRSTipbot> nrpatten The current DRS price at BitTrex {"success":true,"message":"","result":{"Bid":0.00000155,"Ask":0.00000164,"Last":0.00000155}} I have used a couple of things to get it to show only "Last" from the reply but i keep getting errors. Or get certain data from https://bittrex.com/api/v1.1/public/getmarketsummaries Like any info i want from: {"MarketName":"BTC-DRS","High":0.00000161,"Low":0.00000063,"Volume":280917.11022708,"Last":0.00000155,"BaseVolume":0.33696054,"TimeStamp":"2014-10-04T15:14:19.66","Bid":0.00000155,"Ask":0.00000164,"OpenBuyOrders":33,"OpenSellOrders":138,"PrevDay":0.00000090,"Created":"2014-06-18T04:35:38.437"} Thanks for any help
Assuming you've parsed the JSON (e.g. via JSON.parse(str);), you just use whatever property name you want to get at. For example: var info = JSON.parse('{"MarketName":"BTC-DRS","High":0.00000161,"Low":0.00000063,"Volume":280917.11022708,"Last":0.00000155,"BaseVolume":0.33696054,"TimeStamp":"2014-10-04T15:14:19.66","Bid":0.00000155,"Ask":0.00000164,"OpenBuyOrders":33,"OpenSellOrders":138,"PrevDay":0.00000090,"Created":"2014-06-18T04:35:38.437"}'); console.log(info.Bid); Also, on an unrelated matter, typically callback parameters follow the error-first format (e.g. (err, result) instead of (result, err)) in order to be consistent with node core and most other modules on npm.
Gathering information from a textfile. Corona SDK
Earlier I asked about gathering information from API-Link, and I have managed to get out most of the details by using the answar I got. Now ny problem is when another API to get more information This time the file will contain this information: { "username":"UserName", "confirmed_rewards":"0", "round_estimate":"0.00000000", "total_hashrate":"0.000", "payout_history":"0", "round_shares":"0", "workers":{ "UserName.1":{ "alive":"0", "hashrate":"0.000" }, "UserName.2":{ "alive":"0", "hashrate":"0.000" }, "UserName.3":{ "alive":"1", "hashrate":"1517.540", "last_share_timestamp":1369598007 }, "UserName.4":{ "alive":"0", "hashrate":"0.000" } } } And I want to gather each of the workers and print them out. This "workers" could contain multiple information, but always start with "UserName.x", where the username come from the "username" paramter each time. The numbers will always vary from 0 and up I want to gether the information in the same way by accessing the document, and decode and print out all the workers, whatever the numbers of them are. By using the script provided in my last question(look at the link in the start), i was thinking that it would be something like local t = json.decode( txt ) print("Workers: ".. t["workers.UserName.1"]) But this was not the way. Due to the username changing all the time, I was also thinking somthing like print("Workers: ".. t["workers" .. "." .. "username" .. "." .. "1"]) From here I have no clue about how I should gather the information, even when the names and numbers vary Thanks in advance
Here is the perfect solution: local json = require "json" local t = json.decode( jsonFile( "data.json" ) local workers = t.workers for name, user in pairs(workers) do print("--------------------") print(name) for tag, value in pairs(user) do print(tag , value) end end Here are some more info: http://www.coronalabs.com/blog/2011/08/03/tutorial-exploring-json-usage-in-corona/ http://www.coronalabs.com/blog/2011/06/21/understanding-lua-tables-in-corona-sdk/ http://lua-users.org/wiki/TablesTutorial