twingly-search 5.0.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +16 -0
- data/README.md +33 -34
- data/Rakefile +0 -6
- data/examples/find_all_posts_mentioning_github.rb +3 -3
- data/examples/hello_world.rb +2 -2
- data/examples/livefeed_loop.rb +24 -0
- data/lib/twingly/livefeed/client.rb +121 -0
- data/lib/twingly/livefeed/error.rb +28 -0
- data/lib/twingly/livefeed/parser.rb +96 -0
- data/lib/twingly/livefeed/post.rb +66 -0
- data/lib/twingly/livefeed/result.rb +39 -0
- data/lib/twingly/livefeed/version.rb +5 -0
- data/lib/twingly/livefeed.rb +6 -0
- data/lib/twingly/search/client.rb +3 -2
- data/lib/twingly/search/error.rb +6 -5
- data/lib/twingly/search/parser.rb +39 -13
- data/lib/twingly/search/post.rb +65 -21
- data/lib/twingly/search/query.rb +46 -16
- data/lib/twingly/search/result.rb +11 -0
- data/lib/twingly/search/version.rb +1 -1
- data/spec/client_spec.rb +2 -2
- data/spec/error_spec.rb +27 -7
- data/spec/fixtures/incomplete_result.xml +2 -0
- data/spec/fixtures/livefeed/empty_api_key_result.xml +3 -0
- data/spec/fixtures/livefeed/non_xml_result.xml +1 -0
- data/spec/fixtures/livefeed/not_found_result.xml +3 -0
- data/spec/fixtures/livefeed/service_unavailable_result.xml +3 -0
- data/spec/fixtures/livefeed/unauthorized_api_key_result.xml +3 -0
- data/spec/fixtures/livefeed/valid_empty_result.xml +2 -0
- data/spec/fixtures/livefeed/valid_result.xml +79 -0
- data/spec/fixtures/minimal_valid_result.xml +81 -52
- data/spec/fixtures/nonexistent_api_key_result.xml +3 -3
- data/spec/fixtures/service_unavailable_result.xml +3 -3
- data/spec/fixtures/unauthorized_api_key_result.xml +3 -3
- data/spec/fixtures/undefined_error_result.xml +3 -3
- data/spec/fixtures/valid_empty_result.xml +2 -2
- data/spec/fixtures/valid_links_result.xml +36 -0
- data/spec/fixtures/vcr_cassettes/livefeed_valid_request.yml +169 -0
- data/spec/fixtures/vcr_cassettes/search_for_spotify_on_sv_blogs.yml +578 -447
- data/spec/fixtures/vcr_cassettes/search_without_valid_api_key.yml +15 -14
- data/spec/livefeed/client_spec.rb +135 -0
- data/spec/livefeed/error_spec.rb +51 -0
- data/spec/livefeed/parser_spec.rb +351 -0
- data/spec/livefeed/post_spec.rb +26 -0
- data/spec/livefeed/result_spec.rb +18 -0
- data/spec/parser_spec.rb +191 -94
- data/spec/post_spec.rb +25 -6
- data/spec/query_spec.rb +41 -34
- data/spec/result_spec.rb +1 -0
- data/spec/spec_helper.rb +10 -0
- data/twingly-search-api-ruby.gemspec +2 -3
- metadata +44 -24
- data/spec/fixtures/valid_non_blog_result.xml +0 -26
- data/spec/fixtures/valid_result.xml +0 -22975
@@ -6,16 +6,16 @@ module Twingly
|
|
6
6
|
# Parse an API response body.
|
7
7
|
#
|
8
8
|
# @param [String] document containing an API response XML.
|
9
|
-
# @raise [Error] which error depends on the API response (see {Error.
|
9
|
+
# @raise [Error] which error depends on the API response (see {Error.from_api_response}).
|
10
10
|
# @return [Result] containing the result.
|
11
11
|
def parse(document)
|
12
12
|
nokogiri = Nokogiri::XML(document)
|
13
13
|
|
14
|
-
failure = nokogiri.at_xpath('
|
14
|
+
failure = nokogiri.at_xpath('/error')
|
15
15
|
handle_failure(failure) if failure
|
16
16
|
|
17
17
|
data_node = nokogiri.at_xpath('/twinglydata')
|
18
|
-
handle_non_xml_document(
|
18
|
+
handle_non_xml_document(document) unless data_node
|
19
19
|
|
20
20
|
create_result(data_node)
|
21
21
|
end
|
@@ -27,41 +27,67 @@ module Twingly
|
|
27
27
|
result.number_of_matches_returned = data_node.attribute('numberOfMatchesReturned').value.to_i
|
28
28
|
result.number_of_matches_total = data_node.attribute('numberOfMatchesTotal').value.to_i
|
29
29
|
result.seconds_elapsed = data_node.attribute('secondsElapsed').value.to_f
|
30
|
+
result.incomplete_result = incomplete_result?(data_node)
|
30
31
|
|
31
|
-
data_node.xpath('//post
|
32
|
+
data_node.xpath('//post').each do |post|
|
32
33
|
result.posts << parse_post(post)
|
33
34
|
end
|
34
35
|
|
35
36
|
result
|
36
37
|
end
|
37
38
|
|
39
|
+
def incomplete_result?(data_node)
|
40
|
+
data_node.attribute('incompleteResult').value == "true"
|
41
|
+
end
|
42
|
+
|
38
43
|
def parse_post(element)
|
39
44
|
post_params = {}
|
40
45
|
element.element_children.each do |child|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
post_params[child.name] =
|
47
|
+
case child.name
|
48
|
+
when *%w(tags links images)
|
49
|
+
parse_array(child)
|
50
|
+
when "coordinates"
|
51
|
+
parse_coordinates(child)
|
52
|
+
else
|
53
|
+
child.text
|
54
|
+
end
|
46
55
|
end
|
56
|
+
|
47
57
|
post = Post.new
|
48
58
|
post.set_values(post_params)
|
49
59
|
post
|
50
60
|
end
|
51
61
|
|
52
|
-
def
|
62
|
+
def parse_array(element)
|
53
63
|
element.element_children.map do |child|
|
54
64
|
child.text
|
55
65
|
end
|
56
66
|
end
|
57
67
|
|
68
|
+
# TODO: Decide if a class or hash should be used...
|
69
|
+
def parse_coordinates(element)
|
70
|
+
return {} if element.children.empty?
|
71
|
+
|
72
|
+
{
|
73
|
+
latitude: element.at_xpath("latitude/text()"),
|
74
|
+
longitude: element.at_xpath("longitude/text()"),
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
58
78
|
def handle_failure(failure)
|
59
|
-
|
79
|
+
code = failure.attribute('code').value
|
80
|
+
message = failure.at_xpath('message').text
|
81
|
+
|
82
|
+
fail Error.from_api_response(code, message)
|
60
83
|
end
|
61
84
|
|
62
85
|
def handle_non_xml_document(document)
|
63
|
-
|
64
|
-
|
86
|
+
fail ServerError, "Failed to parse response: \"#{document}\""
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_time(time)
|
90
|
+
Time.parse(time)
|
65
91
|
end
|
66
92
|
end
|
67
93
|
end
|
data/lib/twingly/search/post.rb
CHANGED
@@ -1,44 +1,88 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'date'
|
4
|
-
|
5
3
|
module Twingly
|
6
4
|
module Search
|
7
5
|
# A blog post
|
8
6
|
#
|
9
|
-
# @attr_reader [String]
|
10
|
-
# @attr_reader [String]
|
11
|
-
# @attr_reader [String]
|
7
|
+
# @attr_reader [String] id the post ID (Twingly internal identification)
|
8
|
+
# @attr_reader [String] author the author of the blog post
|
9
|
+
# @attr_reader [String] url the post URL
|
10
|
+
# @attr_reader [String] title the post title
|
11
|
+
# @attr_reader [String] text the blog post text
|
12
12
|
# @attr_reader [String] language_code ISO two letter language code for the
|
13
|
-
# language that the post was written in
|
14
|
-
# @attr_reader [
|
15
|
-
#
|
16
|
-
# @attr_reader [
|
17
|
-
#
|
18
|
-
# @attr_reader [
|
19
|
-
#
|
13
|
+
# language that the post was written in
|
14
|
+
# @attr_reader [String] location_code ISO two letter country code for the
|
15
|
+
# location of the blog
|
16
|
+
# @attr_reader [Hash] coordinates a hash containing :latitude and :longitude
|
17
|
+
# from the post RSS
|
18
|
+
# @attr_reader [Array] links all links from the blog post to other resources
|
19
|
+
# @attr_reader [Array] tags the post tags/categories
|
20
|
+
# @attr_reader [Array] images image URLs from the post (currently not populated)
|
21
|
+
# @attr_reader [Time] indexed_at the time, in UTC, when the post was indexed by Twingly
|
22
|
+
# @attr_reader [Time] published_at the time, in UTC, when the post was published
|
23
|
+
# @attr_reader [Time] reindexed_at timestamp when the post last was changed in our database/index
|
24
|
+
# @attr_reader [String] inlinks_count number of links to this post that was found in other blog posts
|
25
|
+
# @attr_reader [String] blog_id the blog ID (Twingly internal identification)
|
26
|
+
# @attr_reader [String] blog_name the name of the blog
|
27
|
+
# @attr_reader [String] blog_url the blog URL
|
20
28
|
# @attr_reader [Integer] blog_rank the rank of the blog, based on authority and language.
|
21
29
|
# See https://developer.twingly.com/resources/ranking/#blogrank
|
22
|
-
# @attr_reader [
|
30
|
+
# @attr_reader [Integer] authority the blog's authority/influence.
|
31
|
+
# See https://developer.twingly.com/resources/ranking/#authority
|
23
32
|
class Post
|
24
|
-
attr_reader :
|
25
|
-
:
|
33
|
+
attr_reader :id, :author, :url, :title, :text, :location_code,
|
34
|
+
:language_code, :coordinates, :links, :tags, :images, :indexed_at,
|
35
|
+
:published_at, :reindexed_at, :inlinks_count, :blog_id, :blog_name,
|
36
|
+
:blog_url, :blog_rank, :authority
|
26
37
|
|
27
38
|
# Sets all instance variables for the {Post}, given a Hash.
|
28
39
|
#
|
29
40
|
# @param [Hash] params containing blog post data.
|
30
41
|
def set_values(params)
|
42
|
+
@id = params.fetch('id')
|
43
|
+
@author = params.fetch('author')
|
31
44
|
@url = params.fetch('url')
|
32
45
|
@title = params.fetch('title')
|
33
|
-
@
|
46
|
+
@text = params.fetch('text')
|
34
47
|
@language_code = params.fetch('languageCode')
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@
|
48
|
+
@location_code = params.fetch('locationCode')
|
49
|
+
@coordinates = params.fetch('coordinates', {})
|
50
|
+
@links = params.fetch('links', [])
|
51
|
+
@tags = params.fetch('tags', [])
|
52
|
+
@images = params.fetch('images', [])
|
53
|
+
@indexed_at = Time.parse(params.fetch('indexedAt'))
|
54
|
+
@published_at = Time.parse(params.fetch('publishedAt'))
|
55
|
+
@reindexed_at = Time.parse(params.fetch('reindexedAt'))
|
56
|
+
@inlinks_count = params.fetch('inlinksCount').to_i
|
57
|
+
@blog_id = params.fetch('blogId')
|
38
58
|
@blog_name = params.fetch('blogName')
|
39
|
-
@
|
59
|
+
@blog_url = params.fetch('blogUrl')
|
40
60
|
@blog_rank = params.fetch('blogRank').to_i
|
41
|
-
@
|
61
|
+
@authority = params.fetch('authority').to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
# @deprecated Please use {#text} instead
|
65
|
+
def summary
|
66
|
+
warn "[DEPRECATION] `summary` is deprecated. Please use `text` instead."
|
67
|
+
text
|
68
|
+
end
|
69
|
+
|
70
|
+
# @deprecated Please use {#indexed_at} instead
|
71
|
+
def indexed
|
72
|
+
warn "[DEPRECATION] `indexed` is deprecated. Please use `indexed_at` instead."
|
73
|
+
indexed_at
|
74
|
+
end
|
75
|
+
|
76
|
+
# @deprecated Please use {#published_at} instead
|
77
|
+
def published
|
78
|
+
warn "[DEPRECATION] `published` is deprecated. Please use `published_at` instead."
|
79
|
+
published_at
|
80
|
+
end
|
81
|
+
|
82
|
+
# @deprecated Please use {#links} instead
|
83
|
+
def outlinks
|
84
|
+
warn "[DEPRECATION] `outlinks` is deprecated. Please use `links` instead."
|
85
|
+
links
|
42
86
|
end
|
43
87
|
end
|
44
88
|
end
|
data/lib/twingly/search/query.rb
CHANGED
@@ -5,11 +5,34 @@ module Twingly
|
|
5
5
|
module Search
|
6
6
|
# Twingly Search API query
|
7
7
|
#
|
8
|
-
# @attr [String]
|
9
|
-
# @attr [String] language language to restrict the query to.
|
8
|
+
# @attr [String] search_query the search query.
|
10
9
|
# @attr [Client] client the client that this query is connected to.
|
11
10
|
class Query
|
12
|
-
attr_accessor :
|
11
|
+
attr_accessor :search_query, :client
|
12
|
+
|
13
|
+
# @deprecated Please use {#search_query} instead
|
14
|
+
def pattern
|
15
|
+
warn "[DEPRECATION] `pattern` is deprecated. Please use `search_query` instead."
|
16
|
+
@search_query
|
17
|
+
end
|
18
|
+
|
19
|
+
# @deprecated Please use {#search_query=} instead
|
20
|
+
def pattern=(search_query)
|
21
|
+
warn "[DEPRECATION] `pattern=` is deprecated. Please use `search_query=` instead."
|
22
|
+
@search_query = search_query
|
23
|
+
end
|
24
|
+
|
25
|
+
# @deprecated Please use {#search_query} instead
|
26
|
+
def language
|
27
|
+
warn "[DEPRECATION] `language` is deprecated. Please use `search_query` instead."
|
28
|
+
@language
|
29
|
+
end
|
30
|
+
|
31
|
+
# @deprecated Please use {#search_query=} instead
|
32
|
+
def language=(language_code)
|
33
|
+
warn "[DEPRECATION] `language=` is deprecated. Please use `search_query=` instead."
|
34
|
+
@language = language_code
|
35
|
+
end
|
13
36
|
|
14
37
|
# @return [Time] the time that was set with {#start_time=}.
|
15
38
|
def start_time
|
@@ -36,7 +59,7 @@ module Twingly
|
|
36
59
|
|
37
60
|
# Executes the query and returns the result.
|
38
61
|
#
|
39
|
-
# @raise [QueryError] if {#
|
62
|
+
# @raise [QueryError] if {#search_query} is empty.
|
40
63
|
# @raise [AuthError] if the API couldn't authenticate you. Make sure your API key is correct.
|
41
64
|
# @raise [ServerError] if the query could not be executed due to a server error.
|
42
65
|
# @return [Result] the result for this query.
|
@@ -50,18 +73,21 @@ module Twingly
|
|
50
73
|
Faraday::Utils.build_query(request_parameters)
|
51
74
|
end
|
52
75
|
|
53
|
-
# @raise [QueryError] if {#
|
76
|
+
# @raise [QueryError] if {#search_query} is empty.
|
54
77
|
# @return [Hash] the request parameters.
|
55
78
|
def request_parameters
|
56
|
-
|
79
|
+
full_search_query = search_query.to_s.dup
|
80
|
+
full_search_query << " lang:#{@language}" unless @language.to_s.empty?
|
81
|
+
full_search_query << " start-date:#{formatted_start_date}" if start_time
|
82
|
+
full_search_query << " end-date:#{formatted_end_date}" if end_time
|
83
|
+
|
84
|
+
if full_search_query.to_s.empty?
|
85
|
+
fail QueryError, "Search query cannot be empty"
|
86
|
+
end
|
57
87
|
|
58
88
|
{
|
59
|
-
|
60
|
-
|
61
|
-
documentlang: language,
|
62
|
-
ts: ts,
|
63
|
-
tsTo: ts_to,
|
64
|
-
xmloutputversion: 2,
|
89
|
+
apikey: client.api_key,
|
90
|
+
q: full_search_query
|
65
91
|
}
|
66
92
|
end
|
67
93
|
|
@@ -95,12 +121,16 @@ module Twingly
|
|
95
121
|
fail QueryError, "Not a Time object" unless time.respond_to?(:to_time)
|
96
122
|
end
|
97
123
|
|
98
|
-
def
|
99
|
-
start_time
|
124
|
+
def formatted_start_date
|
125
|
+
format_timestamp_for_query(start_time) if start_time
|
126
|
+
end
|
127
|
+
|
128
|
+
def formatted_end_date
|
129
|
+
format_timestamp_for_query(end_time) if end_time
|
100
130
|
end
|
101
131
|
|
102
|
-
def
|
103
|
-
|
132
|
+
def format_timestamp_for_query(timestamp)
|
133
|
+
timestamp.to_time.utc.strftime("%FT%T")
|
104
134
|
end
|
105
135
|
end
|
106
136
|
end
|
@@ -12,6 +12,16 @@ module Twingly
|
|
12
12
|
class Result
|
13
13
|
attr_accessor :number_of_matches_returned, :number_of_matches_total,
|
14
14
|
:seconds_elapsed
|
15
|
+
attr_writer :incomplete_result
|
16
|
+
|
17
|
+
# @return [true] if one or multiple servers were too slow to respond
|
18
|
+
# within the maximum allowed query time.
|
19
|
+
# @return [false] if all servers responded within the maximum allowed
|
20
|
+
# query time.
|
21
|
+
# @see https://developer.twingly.com/resources/search/#response
|
22
|
+
def incomplete?
|
23
|
+
@incomplete_result
|
24
|
+
end
|
15
25
|
|
16
26
|
# @return [Array<Post>] all posts that matched the {Query}.
|
17
27
|
def posts
|
@@ -28,6 +38,7 @@ module Twingly
|
|
28
38
|
matches = "@posts, "
|
29
39
|
matches << "@number_of_matches_returned=#{self.number_of_matches_returned}, "
|
30
40
|
matches << "@number_of_matches_total=#{self.number_of_matches_total}"
|
41
|
+
matches << "@incomplete_result=#{self.incomplete?}"
|
31
42
|
|
32
43
|
sprintf("#<%s:0x%x %s>", self.class.name, __id__, matches)
|
33
44
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -90,13 +90,13 @@ describe Client do
|
|
90
90
|
|
91
91
|
let(:query) do
|
92
92
|
query = subject.query
|
93
|
-
query.
|
93
|
+
query.search_query = "something"
|
94
94
|
query
|
95
95
|
end
|
96
96
|
|
97
97
|
it "should raise error on invalid API key" do
|
98
98
|
VCR.use_cassette("search_without_valid_api_key") do
|
99
|
-
expect { subject.execute_query(query) }.to raise_error(AuthError,
|
99
|
+
expect { subject.execute_query(query) }.to raise_error(AuthError, /Unauthorized/)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
data/spec/error_spec.rb
CHANGED
@@ -3,17 +3,37 @@ require "spec_helper"
|
|
3
3
|
describe Twingly::Search::Error do
|
4
4
|
it { is_expected.to be_a(StandardError) }
|
5
5
|
|
6
|
-
|
7
|
-
subject { described_class.from_api_response_message(server_response_message) }
|
6
|
+
let(:message) { "This is the error message!" }
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
describe ".from_api_response" do
|
9
|
+
subject { described_class.from_api_response(code, message) }
|
11
10
|
|
12
|
-
|
11
|
+
context "when given code 401" do
|
12
|
+
let(:code) { 401 }
|
13
|
+
|
14
|
+
it { is_expected.to be_a(AuthError) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when given code 402" do
|
18
|
+
let(:code) { 402 }
|
19
|
+
|
20
|
+
it { is_expected.to be_a(AuthError) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when given code 400" do
|
24
|
+
let(:code) { 400 }
|
25
|
+
|
26
|
+
it { is_expected.to be_a(QueryError) }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when given code 404" do
|
30
|
+
let(:code) { 404 }
|
31
|
+
|
32
|
+
it { is_expected.to be_a(QueryError) }
|
13
33
|
end
|
14
34
|
|
15
|
-
context "when given
|
16
|
-
let(:
|
35
|
+
context "when given another code" do
|
36
|
+
let(:code) { 500 }
|
17
37
|
|
18
38
|
it { is_expected.to be_a(ServerError) }
|
19
39
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<html><body>This is a non XML fixture.</body></html>
|
@@ -0,0 +1,79 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<twinglydata ts="2017-04-11T15:09:48.8750635Z" from="2017-04-10T22:00:00Z" numberOfPosts="3" maxNumberOfPosts="3" firstPost="2017-04-10T22:00:29.267Z" lastPost="2017-04-10T22:11:47.243Z" nextTimestamp="2017-04-10T22:11:47.244Z">
|
3
|
+
<post>
|
4
|
+
<id>727444183574244541</id>
|
5
|
+
<author />
|
6
|
+
<url>http://flinnman.blogg.se/2017/april/mandag-igen.html</url>
|
7
|
+
<title>Måndag igen</title>
|
8
|
+
<text>Hoppla hejsan bloggy!Måndag. Förutom trist hosta på E så mår vi fint. Vi använde helgen till massa umgänge med nära och kära. Kändes extra skönt efter fredagen. Vi hade en tyst minut i en full matsal i polishuset idag. Det var fint! Well. Ny vecka och ... - Läs hela inlägget här</text>
|
9
|
+
<languageCode>sv</languageCode>
|
10
|
+
<locationCode>se</locationCode>
|
11
|
+
<coordinates />
|
12
|
+
<links />
|
13
|
+
<tags>
|
14
|
+
<tag>Jag</tag>
|
15
|
+
</tags>
|
16
|
+
<images />
|
17
|
+
<indexedAt>2017-04-10T22:00:24Z</indexedAt>
|
18
|
+
<publishedAt>2017-04-10T19:11:11Z</publishedAt>
|
19
|
+
<reindexedAt>2017-04-10T22:00:24Z</reindexedAt>
|
20
|
+
<inlinksCount>0</inlinksCount>
|
21
|
+
<blogId>10357806725947705095</blogId>
|
22
|
+
<blogName>Frida L</blogName>
|
23
|
+
<blogUrl>http://flinnman.blogg.se</blogUrl>
|
24
|
+
<blogRank>1</blogRank>
|
25
|
+
<authority>2</authority>
|
26
|
+
</post>
|
27
|
+
<post>
|
28
|
+
<id>6564050082079070812</id>
|
29
|
+
<author />
|
30
|
+
<url>http://malinbs.blogg.se/2017/april/du-ska-hedra-din-fader-och-din-moder.html</url>
|
31
|
+
<title>Du ska hedra din fader och din moder</title>
|
32
|
+
<text>Vilken solig och god helg det har varit på mina breddgrader! Minns för en massa år sedan (25? Eller lite mera?) när Herrn i Huset byggde altanen och samtidigt såg till att det blev eluttag där. Min mammas första kommentar blev: Tänk så bra med ett uttag, ... - Läs hela inlägget här</text>
|
33
|
+
<languageCode>sv</languageCode>
|
34
|
+
<locationCode>se</locationCode>
|
35
|
+
<coordinates />
|
36
|
+
<links />
|
37
|
+
<tags>
|
38
|
+
<tag>Allmänt</tag>
|
39
|
+
</tags>
|
40
|
+
<images />
|
41
|
+
<indexedAt>2017-04-10T22:00:16Z</indexedAt>
|
42
|
+
<publishedAt>2017-04-09T17:12:08Z</publishedAt>
|
43
|
+
<reindexedAt>2017-04-10T22:00:16Z</reindexedAt>
|
44
|
+
<inlinksCount>0</inlinksCount>
|
45
|
+
<blogId>14781290076709326355</blogId>
|
46
|
+
<blogName>Blogga, ett sätt att umgås!</blogName>
|
47
|
+
<blogUrl>http://malinbs.blogg.se</blogUrl>
|
48
|
+
<blogRank>1</blogRank>
|
49
|
+
<authority>4</authority>
|
50
|
+
</post>
|
51
|
+
<post>
|
52
|
+
<id>3062976931264108164</id>
|
53
|
+
<author>josegacel</author>
|
54
|
+
<url>https://josegabrielcelis.wordpress.com/2017/04/09/1476/</url>
|
55
|
+
<title />
|
56
|
+
<text>from Instagram: http://ift.tt/2ofZdhV</text>
|
57
|
+
<languageCode>sv</languageCode>
|
58
|
+
<locationCode />
|
59
|
+
<coordinates />
|
60
|
+
<links>
|
61
|
+
<link>http://www.ift.tt/2ofZdhV</link>
|
62
|
+
<link>http://feeds.wordpress.com/1.0/gocomments/josegabrielcelis.wordpress.com/1476</link>
|
63
|
+
</links>
|
64
|
+
<tags>
|
65
|
+
<tag>Fotos</tag>
|
66
|
+
<tag>Instagram</tag>
|
67
|
+
</tags>
|
68
|
+
<images />
|
69
|
+
<indexedAt>2017-04-10T22:00:28Z</indexedAt>
|
70
|
+
<publishedAt>2017-04-09T22:31:34Z</publishedAt>
|
71
|
+
<reindexedAt>2017-04-10T22:00:28Z</reindexedAt>
|
72
|
+
<inlinksCount>0</inlinksCount>
|
73
|
+
<blogId>1811310581070495497</blogId>
|
74
|
+
<blogName>José Gabriel Celis</blogName>
|
75
|
+
<blogUrl>https://josegabrielcelis.wordpress.com</blogUrl>
|
76
|
+
<blogRank>1</blogRank>
|
77
|
+
<authority>0</authority>
|
78
|
+
</post>
|
79
|
+
</twinglydata>
|