iCulture forum | iPhone, iPad,  iPod touch, Apple TV en iOS

iCulture forum | iPhone, iPad, iPod touch, Apple TV en iOS (https://forum.iculture.nl/)
-   Ontwikkelen voor iOS (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/)
-   -   Webscraping faalt met Content-Type gzip (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/61110-webscraping-faalt-content-type-gzip.html)

justsome 07-06-10 22:04

[Solved!]Webscraping faalt met Content-Type gzip
 
1 Bijlage(n)
Dag allemaal,

Ik wordt zo droevig van m'n probleem dat ik heb besloten het ergens te gaan posten want ik kom er niet uit.

Wanneer ik via NSURLRequest icm een NSURLConnection data van een website probeer te lezen en op de console wil printen krijg ik het volgende resultaat:

  • Wanneer de data simpele HTML is werkt het prima.
  • Wanneer de data gzip compressed it is m'n output leeg
Ik heb met o.a. Wireshark gekeken naar het netwerk verkeer en de HTML headers . M'n app geeft prima aan bij de webserver dat deze gzip ondersteunt. Ook zie ik dat de data binnen gehaald wordt.

Na wat googlen kwam ik er achter dat met de overgang van SDK 2.0 naar 2.1 de gzipped data automatisch gedecompressed wordt. Dit wordt ook bevestigd als ik naar de output kijk van m'n applicatie. Het aantal bytes opgeslagen in m'n NSMutableData is namelijk groter dan de aangeboden (Content-Length) hoeveelheid data.

Citaat:

2010-06-07 21:26:15.512 SimpleWeb[1437:207] Entering -[SimpleWebAppDelegate GetData]
2010-06-07 21:26:15.515 SimpleWeb[1437:207] -[SimpleWebAppDelegate connection:willSendRequest:redirectResponse:]
2010-06-07 21:26:20.726 SimpleWeb[1437:207] -[SimpleWebAppDelegate connection:didReceiveResponse:] Printing headers
{
"Cache-Control" = private;
Connection = close;
"Content-Encoding" = gzip;
"Content-Length" = 19543;

...

2010-06-07 21:26:20.741 SimpleWeb[1437:207] -[SimpleWebAppDelegate connectionDidFinishLoading:] Received 94332 bytes
2010-06-07 21:26:20.741 SimpleWeb[1437:207] -[SimpleWebAppDelegate connectionDidFinishLoading:] failed to init string with data due to encoding
2010-06-07 21:26:20.742 SimpleWeb[1437:207] -[SimpleWebAppDelegate connectionDidFinishLoading:] (null)
Nu valt je waarschijnlijk de foutmelding "failed to init string with data due to encoding" vast op. Dit komt voort uit de volgende code.

Code:

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"%s Received %d bytes",__FUNCTION__, [receivedData length]);
    NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
    if (payloadAsString == nil)
        NSLog(@"%s failed to init string with data due to encoding", __FUNCTION__);
    NSLog(@"%s %@", __FUNCTION__, payloadAsString);
   
    [connection release];
    self.receivedData = nil;
}

De apple documentatie zegt het volgende over de NSString initWithData:encoding functie
Citaat:

Returns nil if the initialization fails for some reason (for example if data does not represent valid data for encoding).
Er gaat dus waarschijnlijk iets fout met de encoding maar ik heb geen idee wat. Wanneer ik namelijk de ontvangen data naar een file op m'n hardeschijf schrijf ziet het er dus hetzelfde uit als wanneer ik direct simpele HTML van een website trek (wat wel werkt).

Ik heb in de bijlage dit simpele projectje toegevoegd zodat mensen er snel mee kunnen testen mochten zij een oplossing denken te weten.

Ik hoop dat iemand een oplossing voor me weet.

Alvast bedankt!

Groetjes,

J






-- edit solved --
Het punt zat hem dus uiteindelijk in het opgeven van verkeerde encoding van de data in de regel
Citaat:

NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
De generiek oplossing. Vervang bovenstaande regel door deze 2.
Citaat:

NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encodingName));

NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:encoding];
Maak een NSString aan in de header die de encodingName tijdelijk opslaat en voeg het volgende toe aan je connection:didReceiveResponse

Citaat:

encodingName = [[NSString alloc] initWithString:[response textEncodingName]];
Nu wordt de naam van de encoding uit de response gehaald, in het geval van het iphoneclub forum in mijn voorbeeld 'charset=ISO-8859-1' (oftewel ISO Latin 1). Vervolgens wordt de bijpassende NSStringEncoding hierbij opgezocht en kan deze netjes meegegeven worden tijdens het initialiseren van de payload string.


Alle tijden zijn GMT +2. Het is nu 15:21.