fix: 페이스북 릴 수집 경로 보강
This commit is contained in:
parent
b01039c223
commit
dcc3eba2e0
@ -32,6 +32,8 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
|||||||
/** Facebook가 데이터센터별로 빈 피드를 돌려주는 경우가 있어 공식 로케일 호스트를 순서대로 시도한다. */
|
/** Facebook가 데이터센터별로 빈 피드를 돌려주는 경우가 있어 공식 로케일 호스트를 순서대로 시도한다. */
|
||||||
private static final List<String> RENDERER_HOSTS = List.of(
|
private static final List<String> RENDERER_HOSTS = List.of(
|
||||||
"www.facebook.com", "ko-kr.facebook.com", "en-gb.facebook.com");
|
"www.facebook.com", "ko-kr.facebook.com", "en-gb.facebook.com");
|
||||||
|
private static final long READER_RECENT_CACHE_SECONDS = 3_600;
|
||||||
|
private static final long READER_BASELINE_CACHE_SECONDS = 2_592_000;
|
||||||
|
|
||||||
private final RestTemplate restTemplate;
|
private final RestTemplate restTemplate;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
@ -60,27 +62,30 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (readerFallbackEnabled) {
|
if (readerFallbackEnabled) {
|
||||||
|
for (ReaderAttempt attempt : readerAttempts(channel.getLastCollectedAt() == null)) {
|
||||||
try {
|
try {
|
||||||
SocialFeedBatch batch = fetchViaReader(channel, false);
|
SocialFeedBatch batch = fetchViaReader(channel, attempt);
|
||||||
if (batch.videos().isEmpty()) batch = fetchViaReader(channel, true);
|
|
||||||
if (!batch.videos().isEmpty()) return batch;
|
if (!batch.videos().isEmpty()) return batch;
|
||||||
|
lastFailure = new IllegalStateException("Facebook Reader 공개 피드에 릴이 없습니다.");
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
lastFailure = e;
|
lastFailure = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
throw new IllegalStateException("Facebook 공개 피드를 읽지 못했습니다: "
|
throw new IllegalStateException("Facebook 공개 피드를 읽지 못했습니다: "
|
||||||
+ (lastFailure == null ? "빈 응답" : friendly(lastFailure)), lastFailure);
|
+ (lastFailure == null ? "빈 응답" : friendly(lastFailure)), lastFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 운영 서버 IP가 Facebook에서 차단될 때 공개 페이지를 브라우저로 읽어 주는 Reader API를 사용한다. */
|
/** 운영 서버 IP가 Facebook에서 차단될 때 공개 페이지를 브라우저로 읽어 주는 Reader API를 사용한다. */
|
||||||
private SocialFeedBatch fetchViaReader(SocialChannel channel, boolean noCache) {
|
private SocialFeedBatch fetchViaReader(SocialChannel channel, ReaderAttempt attempt) {
|
||||||
String source = channel.getSourceUrl().replaceAll("/+$", "") + "/reels/";
|
URI uri = readerUri(channel.getSourceUrl(), attempt.sourceScheme());
|
||||||
URI uri = URI.create("https://r.jina.ai/" + source);
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.set(HttpHeaders.USER_AGENT, "Mozilla/5.0");
|
headers.set(HttpHeaders.USER_AGENT, "Mozilla/5.0");
|
||||||
|
headers.setAccept(List.of(MediaType.TEXT_PLAIN));
|
||||||
|
headers.setAcceptLanguageAsLocales(List.of(Locale.ENGLISH));
|
||||||
headers.set("X-Engine", "browser");
|
headers.set("X-Engine", "browser");
|
||||||
if (noCache) headers.set("X-No-Cache", "true");
|
if (attempt.noCache()) headers.set("X-No-Cache", "true");
|
||||||
else headers.set("X-Cache-Tolerance", "3600");
|
else headers.set("X-Cache-Tolerance", Long.toString(attempt.cacheToleranceSeconds()));
|
||||||
try {
|
try {
|
||||||
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET,
|
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET,
|
||||||
new HttpEntity<>(headers), String.class);
|
new HttpEntity<>(headers), String.class);
|
||||||
@ -94,6 +99,24 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static URI readerUri(String channelUrl, String sourceScheme) {
|
||||||
|
String source = channelUrl.replaceFirst("^https?", sourceScheme).replaceAll("/+$", "") + "/reels/";
|
||||||
|
return URI.create("https://r.jina.ai/" + source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<ReaderAttempt> readerAttempts(boolean baselineCollection) {
|
||||||
|
long fallbackTolerance = baselineCollection
|
||||||
|
? READER_BASELINE_CACHE_SECONDS
|
||||||
|
: READER_RECENT_CACHE_SECONDS;
|
||||||
|
return List.of(
|
||||||
|
new ReaderAttempt("https", true, 0),
|
||||||
|
new ReaderAttempt("http", true, 0),
|
||||||
|
new ReaderAttempt("https", false, READER_RECENT_CACHE_SECONDS),
|
||||||
|
new ReaderAttempt("http", false, fallbackTolerance));
|
||||||
|
}
|
||||||
|
|
||||||
|
record ReaderAttempt(String sourceScheme, boolean noCache, long cacheToleranceSeconds) { }
|
||||||
|
|
||||||
private SocialFeedBatch fetchFromHost(SocialChannel channel, String host) {
|
private SocialFeedBatch fetchFromHost(SocialChannel channel, String host) {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> config = new LinkedHashMap<>();
|
Map<String, Object> config = new LinkedHashMap<>();
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.hlab.yanalyst.domain.social;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class FacebookPageFeedClientTest {
|
class FacebookPageFeedClientTest {
|
||||||
@ -50,4 +52,18 @@ class FacebookPageFeedClientTest {
|
|||||||
.containsExactly("2234599224051571", "926151600080380");
|
.containsExactly("2234599224051571", "926151600080380");
|
||||||
assertThat(batch.videos().get(0).thumbnailUrl()).isEqualTo("https://cdn.example/one.jpg?x=1&y=2");
|
assertThat(batch.videos().get(0).thumbnailUrl()).isEqualTo("https://cdn.example/one.jpg?x=1&y=2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void retriesReaderWithBothSourceSchemesAndUsesLongCacheOnlyForBaseline() {
|
||||||
|
assertThat(FacebookPageFeedClient.readerUri("https://www.facebook.com/phutunet/", "http"))
|
||||||
|
.isEqualTo(URI.create("https://r.jina.ai/http://www.facebook.com/phutunet/reels/"));
|
||||||
|
|
||||||
|
assertThat(FacebookPageFeedClient.readerAttempts(true))
|
||||||
|
.extracting(FacebookPageFeedClient.ReaderAttempt::sourceScheme)
|
||||||
|
.containsExactly("https", "http", "https", "http");
|
||||||
|
assertThat(FacebookPageFeedClient.readerAttempts(true).get(3).cacheToleranceSeconds())
|
||||||
|
.isEqualTo(2_592_000);
|
||||||
|
assertThat(FacebookPageFeedClient.readerAttempts(false).get(3).cacheToleranceSeconds())
|
||||||
|
.isEqualTo(3_600);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user