extract description, image and favicon

This commit is contained in:
2013-12-19 01:18:38 +01:00
parent fa482c9cf5
commit 390f72ec7f
6 changed files with 218 additions and 11 deletions
+137
View File
@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace ReadSharp.Ports.NReadability
{
public class MetaExtractor
{
/// <summary>
/// Gets or sets a value indicating whether [has value].
/// </summary>
/// <value>
/// <c>true</c> if [has value]; otherwise, <c>false</c>.
/// </value>
public bool HasValue { get; set; }
/// <summary>
/// Gets or sets the tags.
/// </summary>
/// <value>
/// The tags.
/// </value>
public IEnumerable<XElement> Tags { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="MetaExtractor"/> class.
/// </summary>
/// <param name="document">The document.</param>
public MetaExtractor(XDocument document)
{
var documentRoot = document.Root;
if (documentRoot == null || documentRoot.Name == null || !"html".Equals(documentRoot.Name.LocalName, StringComparison.OrdinalIgnoreCase))
{
HasValue = false;
return;
}
var headElement = documentRoot.GetChildrenByTagName("head").FirstOrDefault();
if (headElement == null)
{
HasValue = false;
return;
}
IEnumerable<XElement> meta = headElement.GetChildrenByTagName("meta");
IEnumerable<XElement> link = headElement.GetChildrenByTagName("link");
Tags = meta != null ? meta.Concat(link) : link;
HasValue = Tags != null && Tags.Count() > 0;
}
/// <summary>
/// Gets the meta description.
/// </summary>
/// <returns></returns>
public string GetMetaDescription()
{
return SearchCandidates(new Dictionary<string, string>()
{
{ "property|og:description", "content" },
{ "name|description", "content" }
});
}
/// <summary>
/// Gets the meta image.
/// </summary>
/// <returns></returns>
public string GetMetaImage()
{
return SearchCandidates(new Dictionary<string, string>()
{
{ "property|og:image", "content" },
{ "rel|apple-touch-icon", "href" },
{ "rel|apple-touch-icon-precomposed", "href"},
{ "name|msapplication-square310x310logo", "content" },
{ "name|msapplication-square150x150logo", "content" },
{ "name|msapplication-square70x70logo", "content" },
{ "name|msapplication-TileImage", "content" },
{ "rel|image_src", "href" }
});
}
/// <summary>
/// Gets the meta favicon.
/// </summary>
/// <returns></returns>
public string GetMetaFavicon()
{
return SearchCandidates(new Dictionary<string, string>()
{
{ "rel|icon", "href" },
{ "rel|shortcut icon", "href" }
});
}
/// <summary>
/// Searches the candidates.
/// </summary>
/// <param name="candidates">The candidates.</param>
/// <returns></returns>
private string SearchCandidates(Dictionary<string, string> candidates)
{
string result = null;
foreach (var candidate in candidates)
{
string[] type = candidate.Key.Split('|');
XElement element = Tags
.Where(item => String.Equals(item.GetAttributeValue(type[0], null), type[1], StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
if (element != null)
{
result = element.GetAttributeValue(candidate.Value, "");
}
if (result != null && result.Length > 1)
{
break;
}
}
return result;
}
}
}
@@ -49,6 +49,7 @@
<Compile Include="Enums.cs" />
<Compile Include="HtmlUtils.cs" />
<Compile Include="InternalErrorException.cs" />
<Compile Include="MetaExtractor.cs" />
<Compile Include="NReadabilityTranscoder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SgmlDomBuilder.cs" />
@@ -159,6 +159,7 @@ namespace ReadSharp.Ports.NReadability
private Func<AttributeTransformationInput, AttributeTransformationResult> _imageSourceTranformer;
private Func<AttributeTransformationInput, AttributeTransformationResult> _anchorHrefTransformer;
private Func<AttributeTransformationInput, AttributeTransformationResult> _metaTransformer;
#endregion
@@ -249,11 +250,38 @@ namespace ReadSharp.Ports.NReadability
bool titleExtracted = !string.IsNullOrEmpty(extractedTitle);
MetaExtractor metaExtractor = new MetaExtractor(transcodedXmlDocument);
string description = null;
Uri image = null;
Uri favicon = null;
if (metaExtractor.HasValue)
{
description = metaExtractor.GetMetaDescription();
string imageString = metaExtractor.GetMetaImage();
string faviconString = metaExtractor.GetMetaFavicon();
if (imageString != null)
{
imageString = ResolveElementUrl(imageString, transcodingInput.Url);
Uri.TryCreate(imageString, UriKind.Absolute, out image);
}
if (faviconString != null)
{
faviconString = ResolveElementUrl(faviconString, transcodingInput.Url);
Uri.TryCreate(faviconString, UriKind.Absolute, out favicon);
}
}
return
new TranscodingResult(contentExtracted, titleExtracted)
{
ExtractedContent = transcodedContent,
ExtractedTitle = extractedTitle,
ExtractedDescription = description,
ExtractedFavicon = favicon,
ExtractedImage = image,
NextPageUrl = nextPageUrl,
Images = images
};
@@ -1835,6 +1863,13 @@ namespace ReadSharp.Ports.NReadability
set { _anchorHrefTransformer = value; }
}
public Func<AttributeTransformationInput, AttributeTransformationResult> MetaTranformer
{
get { return _metaTransformer; }
set { _metaTransformer = value; }
}
#endregion
}
}
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
@@ -21,6 +22,12 @@ namespace ReadSharp.Ports.NReadability
public string NextPageUrl { get; set; }
public string ExtractedDescription { get; set; }
public Uri ExtractedImage { get; set; }
public Uri ExtractedFavicon { get; set; }
public XDocument RawDocument { get; set; }
public IEnumerable<XElement> Images { get; set; }
+32 -8
View File
@@ -8,6 +8,22 @@ namespace ReadSharp
/// </summary>
public class Article
{
/// <summary>
/// Gets or sets the title.
/// </summary>
/// <value>
/// The title.
/// </value>
public string Title { get; set; }
/// <summary>
/// Gets or sets the description.
/// </summary>
/// <value>
/// The description.
/// </value>
public string Description { get; set; }
/// <summary>
/// Gets or sets the content.
/// </summary>
@@ -16,6 +32,22 @@ namespace ReadSharp
/// </value>
public string Content { get; set; }
/// <summary>
/// Gets or sets the front image.
/// </summary>
/// <value>
/// The front image.
/// </value>
public Uri FrontImage { get; set; }
/// <summary>
/// Gets or sets the favicon.
/// </summary>
/// <value>
/// The favicon.
/// </value>
public Uri Favicon { get; set; }
/// <summary>
/// Gets or sets the images.
/// </summary>
@@ -24,14 +56,6 @@ namespace ReadSharp
/// </value>
public List<ArticleImage> Images { get; set; }
/// <summary>
/// Gets or sets the title.
/// </summary>
/// <value>
/// The title.
/// </value>
public string Title { get; set; }
/// <summary>
/// Gets or sets the next page URL.
/// </summary>
+6 -3
View File
@@ -68,7 +68,7 @@ namespace ReadSharp
/// </summary>
/// <param name="uri">An URI to extract the content from.</param>
/// <param name="bodyOnly">if set to <c>true</c> [only body is returned].</param>
/// <param name="noHeadline">if set to <c>true</c> [no headline (h1) is included].</param>
/// <param name="noHeadline">if set to <c>true</c> [no headline (h1) is included in generated HTML].</param>
/// <returns>
/// An article with extracted content and meta information.
/// </returns>
@@ -124,9 +124,12 @@ namespace ReadSharp
// create article
return new Article()
{
Content = transcodingResult.ExtractedContent,
Images = images,
Title = transcodingResult.ExtractedTitle,
Description = transcodingResult.ExtractedDescription,
Content = transcodingResult.ExtractedContent,
FrontImage = transcodingResult.ExtractedImage,
Images = images,
Favicon = transcodingResult.ExtractedFavicon,
NextPage = transcodingResult.NextPageUrl != null ? new Uri(transcodingResult.NextPageUrl, UriKind.Absolute) : null
};
}