Screen Scraping Error while using NSURL - Objective c - objective-c

I am currently trying to write a program that reads the source code of http://finance.yahoo.com/q?s=aapl and returns the value associated with the average 3 month volume (Avg Vol 3m). I am using NSURL as follows:
NSString *Ticker = #"aaple";
NSString *website = #"http://finance.yahoo.com/q?s=";
NSString *newwebsite = [website stringByAppendingString: Ticker];
NSURL *myURL = [NSURL URLWithString: newwebsite];
NSString *myHomePage = [NSString stringWithContentsOfURL: myURL encoding: NSASCIIStringEncoding error: NULL];
NSLog (#"%#", myHomePage);
However when I print out the source code I notice that the string does not contain the value of the average 3 month volume nor does it contain the reference to it. Similarly I notice that the output of the code is different from the source code of the same website when viewed through a browser (view->developer->view source on chrome). Am I using the correct classes/methods? What can I do so that my program's output is the same as that viewed through my browser?
Btw I am aware that once I have the proper source code I can extract the needed strings using rangeofString, substringToIndex, subStringFromIndex, etc. The focus of this question is how to obtain the correct source code and not what to do to it once I have it.

Related

How to pass the dictionary output value to the url in objective C?

I am working on a proof of concept app that scans a barcode and returns the barcode information as a UPC value(i.e. 9780596001612). I am confused on how to pass that return value to the url(I read some tutorials online but those doesn't seem to have what I am looking for). I have hardcoded the UPC value in the code and I am getting the right response but I want to be able to pass the return value from the barcode scan and pass that value to the url. I recently started working on Objective C and would greatly appreciate your help. Thank you.
- (void) onQRCodeScanned:(NSString*) result {
NSString *theJSONString = [result description];
NSError *theError = NULL;
NSDictionary *theDictionary = [NSDictionary dictionaryWithJSONString:theJSONString error:&theError];
NSArray *results = [theDictionary objectForKey:#"decodedString"];
//results returns 9780596001612
NSString *barcodeUrl = #"http://www.outpan.com/api/get_product.php?barcode=9780596001612";
NSString *resp = [self makeRestAPICall: barcodeUrl];
}
You need to format the string to include the barcode like this (I'm assuming the barcode is the first result of the results variable - it doesn't make sense in it's current format - and that first result does indeed exist):
NSArray *results = [theDictionary objectForKey:#"decodedString"];
NSString *barcode = [results firstObject];
NSString *barcodeUrl = [NSString stringWithFormat:#"http://www.outpan.com/api/get_product.php?barcode=%#",barcode];
NSString *resp = [self makeRestAPICall: barcodeUrl];
Notice how I using stringWithFormat: and then use %# to represent a 'variable' as such, followed by the actual variable I want to include?
You can include primitive types using placeholders like %d (int), %c (char). You use %# to represent an object, such as a NSString.
You can do this for any number of variables, but you'll get an error if the number of placeholders don't match the number of variables!
You may like reading this: String Format Specifiers

How to Use An Escape URL String With Formatting in Objective-C

I need to gather data from a website based on the user's input.
searchString is the user inputted value, such as "search this string".
NSString *withoutSpaces = [searchString stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
Here, I need to replace spaces with %20
Next, I need to put the new string without spaces (replaced with %20) into another string.
NSString *unescapedSearchString = [NSString stringWithFormat:
#"website.com/query?=%22%#%22", withoutSpaces];
The site I need is not really "website.com", but that's just an example. I also need the %22 to remain at the beginning and end.
As you can see, I need the %# to format the new withoutSpaces user input into the website URL.
I did a search and found examples but I could not find any with formatting such as in my case using %#.
What's the best way to "escape" the characters and keep my formatted string? Currently, when I try to access data from the website, it comes back as null. However, when I try a string without the %# formatting and an actual value, I successfully retrieve the data from a website.
Any help is greatly appreciated.
You should do things this way:
NSString *searchString = ... // the raw search string with spaces and all
NSString *quoted = [NSString stringWithFormat:#"\"%#\"", searchString];
NSString *escaped = [quoted stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *urlString = [NSString stringWithFormat:#"website.com?query=%#&value=all", escaped];
BTW - the URL seems a little off. There should be a variable name before the = and after the ?.

Finding extension of an URL

i have a string named url i.e
NSString *url = #"http://sound17.mp3pk.com/indian/barfi/%5BSongs.PK%5D%20
Barfi%20-%2001%20-%20Barfi!.mp3";
Now I want that It should search from last upto the .(dot)
i.e it should search
mp3 in string as it is coming after .(dot) and want to store that mp3 in the temporary variable.
how can i use lastindex(".") or something else to store in temporary variable.
Simple as that:
NSString *extension = [url pathExtension];

App Store ID via Appirater different than ID from plist, and apparently random

I'm having an issue with grabbing the App Store ID from my plist, and using it with Appirater. I NSLogged the URL that was being used when the user pushes "Rate Now", and the App Store ID is way different from the App Store ID I set in Info.plist. No idea where it is getting these numbers from -- they are a different set of 9 numbers each time. This is really strange.
The code in Appirater.m that deals with grabbing the App Store ID and using it in the link looks like this: NSString *const kAppiraterAppIdBundleKey = #"AppStoreId";
NSString *templateReviewURL = #"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID";
....
+ (NSString*)appStoreAppID {
NSString* value = [[[NSBundle mainBundle] infoDictionary] objectForKey:kAppiraterAppIdBundleKey];
NSAssert1(value, #"Error - you have not specified %# property in your info.plist", kAppiraterAppIdBundleKey);
return value;
}
//...
+ (void)rateApp {
//...
NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:#"APP_ID" withString:[NSString stringWithFormat:#"%d", [self appStoreAppID]]];
//...
}
I added a field in the plist called "AppStoreId", and entered the 9 digit code. I made it a string type. Now, the code runs perfectly when I replace "APP_ID" with the actual 9 digit code in that iTunes link above, but when I keep it as APP_ID, I get the error "Cannot connect to the iTunes Store.", and the NSLog output has 9 random numbers in the link, and again, they are different each time.
This is probably an easy fix, but I can't seem to figure it out.
Random numbers? You're using:
[NSString stringWithFormat:#"%d", [self appStoreAppID]]
where appStoreAppID is an NSString.
So you're replacing "APP_ID" with the pointer to the NSString, not the contents of the NSString.
Just use %# instead of %d.

Why does this NSString created from an NSData object fail to show it has contents?

Why does the following code produce the logging at the bottom ?
Here is the anomaly- my second NSLog should print the chrStr but produces nothing, empty, which is verified by this debug command:
(gdb) po chrStr
object returns empty description
However, the third NSString where I re-convert the NSString back to NSData object DOES display the the data, the same value as in the first NSLog, as it should. This would indicate to me that chrStr must have actual contents. But it seems not to be so from the NSLOG or the po command. Why ?
NSString *login;
NSString *pass;
// Purpose: NSString *loginString = [NSString stringWithFormat:#"\000%#\000%#", login, pass];
login = #"Loginname"; // text string1
pass = #"Password"; // text string2
// convert text strings to data objects
NSData *subData1 = [login dataUsingEncoding:NSUTF8StringEncoding];
NSData *subData2 = [pass dataUsingEncoding:NSUTF8StringEncoding];
// embed a NULL into new NSData object
NSMutableData *data = [NSMutableData data];
unsigned char zeroByte = 0;
[data appendBytes:&zeroByte length:1];
// append string1, NULL, string2 to data object
[data appendData:subData1];
[data appendBytes:&zeroByte length:1];
[data appendData:subData2];
NSLog(#"1.NSData: %#", data); // print data object
// create a character string from data object
NSString *chrStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"2.NSString: %#", chrStr); // print character string
// create data object from string object
NSData *chrData = [chrStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"3.NSDATA: %#", chrData); // print data object
Produces:
[1071:207] 1.NSData: 004c6f67 696e6e61 6d650050 61737377 6f7264
[1071:207] 2.NSString:
[1071:207] 3.NSDATA: 004c6f67 696e6e61 6d650050 61737377 6f7264
This is a real mystery to me. If chrStr is empty then 3-NSDATA could not display its info, but it does !
What am I trying to accomplish ? Well, check my very first comment line: // purpose:
That line when uncommented produces a warning, even though it actually works, so I was trying to do it another way that allowed me to have a clean compile. If you see a better way to accomplish that objective, I all eyes and ears. But please don't dwell on why that #"\000%#\000%#" string is necessary, start out accepting that it is. Thanks.
In C (and therefore objective-c), a null byte is used to represent the end of a string. When you create the string object, it takes all of the data you have given it without parsing, which is why you can convert it back to data successfully. However, when you display the string, the system reads the string up to the first null byte, which is the first byte. Therefore, the string contains data, but any system functions which read byte by byte instead of using the strings returned length will think it is empty. When you work with non-displayable characters, you should try to use data objects over string objects as often as possible.