fix: 페이스북 릴 수집 경로 보강
This commit is contained in:
parent
b01039c223
commit
dcc3eba2e0
@ -32,6 +32,8 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
||||
/** Facebook가 데이터센터별로 빈 피드를 돌려주는 경우가 있어 공식 로케일 호스트를 순서대로 시도한다. */
|
||||
private static final List<String> RENDERER_HOSTS = List.of(
|
||||
"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 ObjectMapper objectMapper;
|
||||
@ -60,12 +62,14 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
||||
}
|
||||
}
|
||||
if (readerFallbackEnabled) {
|
||||
try {
|
||||
SocialFeedBatch batch = fetchViaReader(channel, false);
|
||||
if (batch.videos().isEmpty()) batch = fetchViaReader(channel, true);
|
||||
if (!batch.videos().isEmpty()) return batch;
|
||||
} catch (IllegalStateException e) {
|
||||
lastFailure = e;
|
||||
for (ReaderAttempt attempt : readerAttempts(channel.getLastCollectedAt() == null)) {
|
||||
try {
|
||||
SocialFeedBatch batch = fetchViaReader(channel, attempt);
|
||||
if (!batch.videos().isEmpty()) return batch;
|
||||
lastFailure = new IllegalStateException("Facebook Reader 공개 피드에 릴이 없습니다.");
|
||||
} catch (IllegalStateException e) {
|
||||
lastFailure = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Facebook 공개 피드를 읽지 못했습니다: "
|
||||
@ -73,14 +77,15 @@ public class FacebookPageFeedClient implements SocialFeedClient {
|
||||
}
|
||||
|
||||
/** 운영 서버 IP가 Facebook에서 차단될 때 공개 페이지를 브라우저로 읽어 주는 Reader API를 사용한다. */
|
||||
private SocialFeedBatch fetchViaReader(SocialChannel channel, boolean noCache) {
|
||||
String source = channel.getSourceUrl().replaceAll("/+$", "") + "/reels/";
|
||||
URI uri = URI.create("https://r.jina.ai/" + source);
|
||||
private SocialFeedBatch fetchViaReader(SocialChannel channel, ReaderAttempt attempt) {
|
||||
URI uri = readerUri(channel.getSourceUrl(), attempt.sourceScheme());
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
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");
|
||||
if (noCache) headers.set("X-No-Cache", "true");
|
||||
else headers.set("X-Cache-Tolerance", "3600");
|
||||
if (attempt.noCache()) headers.set("X-No-Cache", "true");
|
||||
else headers.set("X-Cache-Tolerance", Long.toString(attempt.cacheToleranceSeconds()));
|
||||
try {
|
||||
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET,
|
||||
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) {
|
||||
try {
|
||||
Map<String, Object> config = new LinkedHashMap<>();
|
||||
|
||||
@ -2,6 +2,8 @@ package com.hlab.yanalyst.domain.social;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class FacebookPageFeedClientTest {
|
||||
@ -50,4 +52,18 @@ class FacebookPageFeedClientTest {
|
||||
.containsExactly("2234599224051571", "926151600080380");
|
||||
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