maandag 23 juli 2007

Webscreen scraping III

Een httpwebrequest is een bijzondere klasse.
Het http protocol is geen makkelijk protocol en kan afhankelijk van de protocol instellingen zowel als server en client verschillen gedrag vertonen.

Bij het herhaaldelijk gebruiken van een webrequest ging er ergens iets mis.
System.Net.WebException: The underlying connection was closed:

Oplossingen die niet werkten:
System.Threading.Thread.Sleep(2000)
--1000 verbindingen direct achter elkaar vind geen enkele server/router leuk
ServicePointManager.DefaultConnectionLimit = 10
--meer dan standaard 2 (mischien een connectie die busy was oid)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls
--we werken via HTTPS mischien helpt dat
lHttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
lHttpWebRequest.SendChunked = True
--mischien een fout in certificaat handeling(incomplete transmissie) daarom chunked ipv streamed
lHttpWebRequest.Method = "GET"
--get ipv post ivm met certificaat fout (de fout lag zeker bij een post aktie)
lHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30; MEGAUPLOAD 1.0)"
--een moderne browser string (alles anders dan IEXplore deed het zowiezo niet)
lHttpWebRequest.Timeout = 30000
--timeout maakt geen verschil
lHttpWebRequest.KeepAlive = False
--keep conneciton alive (als de verbinding open blijft kan .Net denken dat hij open staat terwlijk de server hem allang dicht heeft gegooid)
'lHttpWebRequest.ProtocolVersion = HttpVersion.Version11
currentServicePoint = lHttpWebRequest.ServicePoint
currentServicePoint.MaxIdleTime = 5000
--max idle time for connectie daarna moet hij opnieuw gemaakt worden
currentServicePoint.Expect100Continue = False
--er is een fout in .Net dat een 100 continue en een 100 close melding door elkaar gehaald worden

'vanaf hier standaard code
'url = "https://blablabla.com
lHttpWebResponse = CType(lHttpWebRequest.GetResponse, HttpWebResponse)
lHttpWebResponseStream = lHttpWebRequest.GetResponse.GetResponseStream
str = lHttpWebResponseStream

donderdag 19 juli 2007

Webscreen scraping II

Soms, is het leven moeilijk.


Screenscraping via .Net werkt met de HttpWebRequest class.

Dim lHttpWebRequest As HttpWebRequest
Dim lHttpWebResponse As HttpWebResponse
Dim lHttpWebResponseStream As Stream
lHttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
lHttpWebResponse = CType(lHttpWebRequest.GetResponse, HttpWebResponse)
lHttpWebResponseStream = lHttpWebRequest.GetResponse.GetResponseStream

Zoals ik in mijn vorige post heb verteld werkt dat niet altijd goed. Nu blijkt dus het probleem te zijn dat mijn HttpWebRequest geen user string meegeeft die geaccepteerd word.

De oplossing:
lHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"

ps.
Bij een httpwebrequest altijd een WebException afvangen kijken naar de status en vervolgens de response stream uitlezen waar meestal de server foutmelding in staat

lHttpWebResponseStream = ex.Response.GetResponseStream

dinsdag 17 juli 2007

Web screen scraping

Bij Twice werk ik als docent ook als importeur van een aantal websites. De meeste websites benader ik met de WebRequest class en kan ik via strings en regular expressions alles vinden. Meestal ben ik met
een druk op een knop en een kwartiertje wachten klaar. Soms vinden websites het echter nodig om zichzelf een nieuw uiterlijk aan te meten en dan werken mijn regex niet meer goed.

Eens in de zoveel tijd veranderd er een website zo heftig dat het niet meer leuk is.
Sommige moderne websites werken met sessies en als dat nog niet erg genoeg is zijn sommige websites gebaseerd op javascript en .Net technologien (ajax ben ik nog niet echt tegen gekomen)

Bij sommige websites kan ik niet met de webrequest aan de gang maar moet ik met de WebBrowser control werken. De webbrowser control biedt de mogelijkheid om in de DOM van het html document te werken en javascript goed uit te voeren. Verder zorgt de webbrowser er voor dat post en put informatie automatisch goed terecht komt.

Voor de selectie van een dropdown list en het klikken van een A link heb ik de volgende code gebruikt:

'Laad het juiste element (id=quickCountry)O
Dim countryList As HtmlElement = wbsap.Document.GetElementById("quickCountry")
'deselecteer alle elementen
For Each s As HtmlElement In countryList.All
s.SetAttribute("selected", "")
Next
'selecteer NL ->element 23
countryList.All.Item(23).SetAttribute("selected", "True")


Het direct aanpassen van de countrylist naar een element
countryList.InnerText = "

dinsdag 10 juli 2007

Microsoft Download Center

Microsoft heeft op het grote web de volgende website met heel veel downloads, patches en service packs : http://www.microsoft.com/downloads/

Een van mijn grote problemen met het aanbod is dat de meeste bestanden heel slecht genaamd zijn. Ik ben momenteel Microsoft Virtual PC aan het downloaden en de naam het installatie programma is setup.exe, een naam die nog niet in mijn download folder stond(...).

De naam van de .Net framework 1.1 is dotnetfx.exe
De naam van het .Net framework 2.0 is dotnetfx.exe

Ze kiezen voor een duidelijke naam!....

Een betere naam voor de VPC setup had VPSsetup.exe geweest (desnoods met MS ervoor)
Een betere naam voor het framework: dotNetFx10.exe en dotNetFx20.exe

Nu begrijp ik wel dat visual studio projecten standaard de setup.exe naam aangeven en het lastig is aan te passen, maar moeilijk is het niet.

maandag 9 juli 2007

Office 2007 (double line breaks)

Hoi Daar,

Sinds ik vista heb geinstalleerd werk ik ook met Office 2007. Kort voordat ik mijn laptop kreeg heb ik kort met 2007 gewerkt maar nu werk ik er full time mee.

Een punt dat me erg irriteerde was een dubbele "line break" na een enter.
De meeste html/visual studio ontwikkelaars zullen het wel herkennen dat de enter toets een nieuwe paragraaf/alinea start die dus een extra regel ruimte reserveerd.

Na het formuleren van een 100 tal word help en google zoek opdrachten kwam ik niet uit het probleem. Verder kijkend op google kwam ik uit op computer idee forum waar het antwoord staat.

Hier de menu opties die je kan gebruiken om de dubbele line breaks te verwijderen

Op de Home ribbon bij de Styles
Rechts klikken op Normal en dan Modify
Dan links onder format -> paragraph
Spacing after op 0 zetten (ipv 10)

Daarna even alles selecteren en op normal zetten

maandag 2 juli 2007

LinearGradient

Iedereen die wel eens wat heeft moeten tekenen in een Paint event weet dat het niet altijd even makkelijk is of anders heel veel werk. Tijdens de DevDays werd er gezeged dat een Gradient (overgang tussen twee kleuren) elke applicatie een stuk mooier maakt.

Voor mijn PDA heb ik een simpele klok applicatie geschreven maar iedereen die hem zag vond hem vreselijk lelijk. Daarom wilde ik graag een LinearGradient toevoegen.

Normaal gesproken gaat dat in twee stappen:
-Maak een Brush object aan (LinearGradientBrush)
-Gebruik van een Graphics object de FillRectangle methode en geef de brush als parameter mee. (De fillXX methode verwacht ook een Rectangle(x,y,width,height)

Nu zal je natuurlijk altijd zien dat een LinearGradientBrush niet beschikbaar is in een Windows Mobile/PDA omgeving.

Ik wilde natuurlijk wel een mooie gradient in mijn applicatie dus ik moest aan het werk. Mijn gereedschap was als volgt:

Een kleur bestaat uit drie kanalen -> red green blue met een waarden van 0 - 255
De nul waardes zijn zwart en de 255 waardes zijn de volledige kleur. Combinaties van kleuren zijn te maken door de verschillende kleuren meer of minder te gebruiken.

Ik kan in een For loopje kleuren aanpassen

De Solidbrush kan ik gebruiken om in één kleur te tekenen.

Het graphics object heeft een fillrect waarmee ik een pixel breed en de gewenst hoogte kan tekenen.

De code die ik gebruikt heb is als volgt:

///
/// Deze code tekend een gradient van de kleur donker zwart (50,10,50)
/// naar de kleur groen (50,240,50)
///

///
void drawGradient(Graphics g)
{
for (int x = 10; x < (this.Width + 10); x++)
{
Color c = Color.FromArgb(50,x , 50);
Rectangle rect = new Rectangle(x -10, 0, 1, this.Height);
Brush b = new SolidBrush(c);
g.FillRectangle(b, rect);
}
}

Dit is natuurlijk geen code die:

Mooi geschieden is van zijn container(breedte 255 pixels + en er komt een exception)
Werkt met variabele kleuren (van zwartig naar groening)
Logische parameters heeft (breedte/hoogte)
Code die goed omgaat met mogelijke exceptions

Daarom heb ik ook meteen maar een functie gemaakt in een static class die daar iets beter mee omgaat:

public static void drawGradient(Graphics g, int x, int y, int width, int height, Color start,Color end)
{
for (int i = x; i < width; i++)
{
int rs, gs, bs = 0;
rs = start.R;
gs = start.G;
bs = start.B;

int re, ge, be = 0;
re = end.R;
ge = end.G;
be = end.B;

//float diffR, diffG, diffB = 0F;
int ri, gi, bi;
ri = calcDiff(rs,re,width,i);
gi = calcDiff(gs, ge, width, i);
bi = calcDiff(bs, be, width, i);
if (gi > 255)
gi = gi;
Color c = Color.FromArgb(ri,gi,bi);
Brush b = new SolidBrush(c);

Rectangle r = new Rectangle(x+i, y, 1, height);
g.FillRectangle(b, r);
}
}

static int calcDiff(int rs, int re, int width, int i)
{
float diff = 0F;
int move = re - rs;
float mt, wt;
mt = (float)move;
wt = (float)width;
diff = (mt / wt) * i;
if (move > 0)
move = move;
diff += rs;

return (int)diff;
}

Snaplines

Bij het gebruik van Controls in visual studio bij het creeren van windows applicaties bieden de meeste controls snaplines aan. Snaplines langs de randen van controls kunnen gebruikt worden om op een makkelijke manier controls uit te lijnen.



De control hierboven heeft 2 actieve snaplines. Eentje om de linker rand van het vierkant en eentje op de onder rand van het rode blok in de control. Deze user control biedt niets anders aan dan een vierkant blok met in de kern een rood blok.

Zelf heb ik aan deze control snaplines toe gevoegd. Het toeveogen van snaplines aan een control is heel eenvoudig. Visual studio kijkt bij het openen van een control naar of er een Designer attribute aanwezig is. Aan de hand van de Designer attribute kan Visual Studio bepalen welke class hij moet gebruiken als 'Designer'. In de Designer class zitten een aantal methodes die een aanta returns verwachten.

Door het overriden van deze functies/properties kan je zaken aanpassen. Door bijvoorbeeld het overriden van de property:
public override System.Collections.IList SnapLines

Kan je een nieuwe return value opgeven van bijvoorbeeld:
ArrayList snapLines = base.SnapLines as ArrayList;
snapLines.Add(new SnapLine(SnapLineType.Left, 50));

Door deze aktie heb je nu een snapline die 50 pixels rechs van de linker rand een linker rand toond.

In mijn control, de CenterSquare heb ik een flink aantal snaplines toegevoegd:

public class CenterSquareSnapLines : ControlDesigner
{

public override System.Collections.IList SnapLines {
get
{
ArrayList snapLines = base.SnapLines as ArrayList;
CenterSquare c = this.Control as CenterSquare;
if (c != null)
{
snapLines.Add(new SnapLine(SnapLineType.Left, c.BorderDistance));
snapLines.Add(new SnapLine(SnapLineType.Right, c.Height - c.BorderDistance));
snapLines.Add(new SnapLine(SnapLineType.Top, c.BorderDistance));
snapLines.Add(new SnapLine(SnapLineType.Bottom, c.Width - c.BorderDistance));
snapLines.Add(new SnapLine(SnapLineType.Top, 5));
}
else
{
//Debug message here!
}
return snapLines;
}
}

}//einde class

Deze designer heb ik vervolgens toegevoegd aan mijn CentrerSquare class door het designer attribute:
[Designer(typeof(CenterSquareSnapLines))]
public partial class CenterSquare : UserControl
{
//implementatie heir
}

Bijzonderheden:
De ControlDesigner class heeft een property Control die de huidige control in design time toont. Door het casten van deze control kan je bij alle properties komen.
De snaplines property is van het type Ilist compleet zonder type checking.
Snaplines hebben een snaplinetype enumeration let op, sommige items van de enumeration zijn niet altijd zichtbaar!
In design time in VS kan je op Alt klikken om de control zonder snaplines te verplaatsen.
In design time kan je in VS op Ctrl klikken om de control te kopieren.
Meer lezen over de designer kan op : http://msdn2.microsoft.com/en-us/library/ms171830.aspx

ps. Ik zal binnenkort eens kijken of ik een mooiere opmaak kan krijgen.