/// <summary> /// Gets the details of the provided Pokemon. /// </summary> /// <param name="id">The Pokemon number.</param> /// <returns>The details of the Pokemon, or null if the id is not valid.</returns> public async Task <PokemonDetails> GetDetails(int id) { PokemonReference reference = await this.GetReference(id).ConfigureAwait(false); if (reference == null) { return(null); } // We currently do not cache Pokemon details. We probably should add this in the // long term to improve performance and reduce the load on the Bulbapedia servers. return(await this.bulbapedia.GetDetails(reference).ConfigureAwait(false)); }
/// <summary> /// Gets detailed information about the provided Pokemon. /// </summary> /// <param name="reference">The Pokemon reference.</param> /// <returns>The detailed information about the Pokemon.</returns> public async Task <PokemonDetails> GetDetails(PokemonReference reference) { IDocument document = await this.GetPage(reference.Name + "_(Pokémon)").ConfigureAwait(false); // The layout of the body content is as follows: // - Table with the top navigation bar (to navigate between Pokemon species) // - Table with Pokemon information (right side panel) // - One or more paragraph tags with the leading introduction of the Pokemon (this is what we want). // - A div element that encapsulates the table of contents. // Note that HTML tag names are always upper case (https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName) string description = string.Join("\n", document.GetElementById("mw-content-text").Children .SkipWhile(e => e.TagName == "TABLE") .TakeWhile(e => e.TagName == "P") .Select(e => e.TextContent.Trim()) .Where(line => !string.IsNullOrWhiteSpace(line))); // This is the table on the left of the page with the general info of the Pokemon. IElement infoTable = document.QuerySelectorAll("table + table.roundy") .Single(table => table.QuerySelector("table table > tbody > tr:first-child > td:first-child > big > big > b") != null); string catchRate = this.GetPokemonInfoPanelValue(infoTable, "Catch rate"); string baseExpYield = this.GetPokemonInfoPanelValue(infoTable, "Base experience yield"); string hatchTimeDescription = this.GetPokemonInfoPanelValue(infoTable, "Hatch time"); string baseFriendship = this.GetPokemonInfoPanelValue(infoTable, "Base friendship"); int[] hatchTime = hatchTimeDescription == null ? new[] { 0 } : hatchTimeDescription.Split('-').Select(s => this.TryParseInt32(s, 0)).ToArray(); return(new PokemonDetails { Number = reference.Number, Name = reference.Name, Description = description, Types = this.GetTypes(infoTable), CatchRate = this.TryParseInt32(catchRate, 0), BaseExperienceYield = this.TryParseInt32(baseExpYield, 0), HatchTimeMin = hatchTime[0], HatchTimeMax = hatchTime.Length > 1 ? hatchTime[1] : hatchTime[0], BaseFriendship = this.TryParseInt32(baseFriendship, 0), }); }