블로그를 만들고 구글과 네이버 등에 등록을 하고 보니 사이트맵을 제출해야 한다고 한다. 사이트맵이라고 하면 사용자들이 사이트 구조를 파악하기 쉽도록 메뉴를 보기좋게 나열해 놓은 페이지만 생각했었는데, 알고보니 XML 파일로 검색엔진이 사이트 내의 링크 목록을 크롤링하기 쉽게 알려주는 작업이 필요한 것이었다.
사이트맵이 없더라도 검색엔진이 알아서 페이지들을 크롤링하고 링크를 수집할 수는 있지만, 사이트 구조가 복잡하거나 쉽게 노출되지 않는 페이지가 있는 경우에는 사이트 내의 콘텐츠가 검색 결과에 잘 노출되지 않기 때문에 미리 링크가 정리된 XML 사이트맵을 제공해 주는것이 좋다고 한다. 구글과 네이버 검색 등록시에 사이트맵이 제출되어 있으면 더 좋은 점수를 받는다.
웹에서 사이트 주소를 입력하면 XML 파일을 생성해주는 서비스를 하는 사이트들이 있어 그런 곳을 이용하면 쉽게 만들 수 있다고 한다. 하지만 Django로 작업을 한 경우에는 Django 내에 사이트맵을 생성해주는 프레임워크가 내장되어 있어 이것을 이용하면 사이트의 내용이 추가될 때마다 자동으로 업데이트되는 XML 사이트맵을 쉽게 만들 수 있다. 이 포스트에서는 Django를 이용해 사이트맵을 만드는 방법을 정리해 본다. Django 공식 documentation 내용을 주로 참고했다.
#1. Sitemap 프레임워크는 sites 프레임워크가 활성화 되어 있어야 동작한다.
우선 프로젝트의 settings.py
파일의 INSTALLED_APPS
목록에 'django.contrib.sites'
와django.contrib.sitemaps'
를 추가해 주고 settings.py
안의 적당한 곳에 'SITE_ID = 1'
이라고 지정해 준다.
[ settings.py ]
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites', # 추가
'django.contrib.sitemaps', # 추가
..기타 설치한 app들..
]
SITE_ID = 1 # 추가
#2. settings.py
안의 TEMPLATES
설정에서 다음 두 가지 설정이 되어있는지 확인한다. Django 프로젝트를 생성할때 디폴트로 생성되므로 바꾼 적이 없다면 그대로 두면 된다.
[ settings.py ]
'BACKEND': 'django.template.backends.django.DjangoTemplates'
'APP_DIRS': True
#3. 사이트맵의 url 을 설정해 주어야 한다. 프로젝트의 가장 상위의 urls.py
에 다음을 추가해 준다.
[ urls.py ]
from django.contrib.sitemaps.views import sitemap
path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, name='sitemap')
이제 도메인/sitemap.xml
에 접근하면 Django 가 동적으로 sitemap 을 생성해 준다. Django 는 sitemap.xml
의 위치를 기준으로 현재 위치와 그보다 하위의 URL 만 포함시키므로, 특별한 이유가 없다면 프로젝트의 root 디렉토리에 sitemap.xml 을 생성해주는것이 좋다.
#4. 사이트맵은 django.contrib.sitemaps 패키지의 Sitemap 클래스를 이용해서 생성한다.
사이트맵의 내용을 담은 sitemaps.py 파일을 따로 작성해 주면 편하다. 우선 블로그의 Post 모델을 불러와서 모든 publish 된 포스트에 대한 링크를 포함하고 있는 사이트맵을 만들어 본다. sitemaps.py 에 새로운 클래스를 생성하고, urls.py 에서 해당 클래스를 포함한 딕셔너리를 #3.에서 지정한 'sitemap.xml' 에 전달해준다.
[ sitemaps.py ]
from django.contrib.sitemaps import Sitemap
from .models import Post
class PostSitemap(Sitemap):
changefreq = 'weekly'
priority = 0.9
def items(self):
return Post.objects.all().filter(published_date__isnull=False).order_by('-published_date')
def lastmod(self, obj):
return obj.modify_date
[ urls.py ]
sitemaps = {
'posts':PostSitemap,
}
XML 사이트맵은 URL 정보를 표시하기 위해 기본적으로 <loc> 태그를 반드시 포함해야 하고, 추가로 <lastmod>, <changefreq>, <priority> 태그를 이용해 부가 정보를 표시해줄 수 있다(기타 자세한 사항은 sitemaps.org 를 참고).
Sitemap 클래스를 사용하기 위해 items()
메서드가 반드시 포함되어야 하는데, 위에서처럼 QuerySet 을 리턴해주면 사이트맵 제공을 위한 object의 목록을 만들어 준다.
Django 에서는 Sitemap 클래스 내의 location()
메서드 혹은 location='value'
속성을 이용해서 <loc>
태그 안에 들어갈 URL을 제공해줄 수 있는데, 따로 명시하지 않으면 items()
에서 가져온 object의 get_absolute_url()
을 이용해 얻은 URL을 생성해 준다.
<lastmod>
는 해당 아이템이 최종 수정된 날짜로, 메서드 lastmod()
또는 속성 lastmod='value'
값으로 지정해줄 수 있다. 반드시 파이썬의 datetime
값으로 지정해야 한다. 이 블로그의 경우는 포스트마다 최근 수정한 날짜(modify_date
)를 기록하고 있어 그 값을 lastmod 값으로 지정해주도록 메서드를 정의했다.
<changefreq>
는 메서드 changefreq()
또는 changefreq='value'
속성으로 지정해줄 수 있다. 속성으로 지정해 주는 경우 위처럼 'weekly' 또는 'always', 'hourly', 'daily', 'monthly', 'yearly', 'never' 등으로 지정해줄 수 있다. 이 속성은 검색엔진에 해당 내용이 얼마나 자주 바뀌는지를 알려 주는데, 그냥 참고용 정보일 뿐이고 검색엔진이 지정된 주기로 인덱싱하도록 명령을 내릴 수 있는것은 아니므로, 메서드를 이용해서 아주 엄밀하게 지정해줄 필요는 없을것같고 대략 위의 속성 중에 골라서 지정해주면 될 듯하다.
<priority>
는 역시 메서드 또는 속성으로 지정할수 있는데, 0에서 1 사이의 값을 지정하면 된다. 지정해주지 않는 경우 기본 값은 0.5 이다. 이 값은 해당 사이트 내에서 현재 아이템이 얼마나 중요도를 갖는지를 검색엔진에 알려 주려는 목적이고, 다른 사이트와 비교해서 중요도를 나타내는 것은 아니기 때문에 무조건 높다고 좋은것은 아니다. 사이트 관리자가 재량껏 지정하면 되겠다.
#5. 위에서는 models.py
에 정의된 Post
모델에서 QuerySet을 읽어와서 각각의 item을 동적으로 제공했는데, 사이트의 메인 페이지나 기타 정적인 view의 사이트맵을 제공해야 할 필요가 있다.
이를 위해서 sitemaps.py
에 정적인 페이지를 위한 클래스를 새로 만들어 준다. items()
에 urls.py
에서 지정한 view의 이름을 리스트 형식으로 리턴해 주고, 이를 urls.py
의 sitemaps
변수에 포함시켜 주면 된다.
우선 위에서 작업한 sitemaps.py 에 다음 내용을 추가해준다.
[ sitemaps.py ]
from django.urls import reverse
class StaticViewSitemap(Sitemap):
priority = 0.5
changefreq = 'weekly'
def items(self):
return [
'index',
'myblog:post_list',
'myblog:post_title_list',
'myblog:archive_index',
'myblog:category_list',
'myblog:bookmark_list',
'myblog:tag_cloud',
]
def location(self, item):
return reverse(item)
상응하는 urls.py 의 내용은 다음과 같다.
[ urls.py (프로젝트 root) ]
urlpatterns = [
..기타 url 설정..
path('', blog_views.IndexView.as_view(), name='index'),
path('myblog/', include('myblog.urls', namespace='myblog')),
]
sitemaps = {
'posts':PostSitemap,
'static':StaticViewSitemap,
}
앱 디렉토리 내의 urls.py
[ myblog/urls.py ]
app_name='myblog'
urlpatterns = [
..기타 url 설정..
path('post/', views.PostListView.as_view(), name='post_list'),
path('posttitle/', views.PostListTitleOnlyView.as_view(), name='post_title_list'),
path('archive/', views.PostArchiveIndexView.as_view(), name='archive_index'),
path('category/', views.CategoryListView.as_view(), name='category_list'),
path('bookmark/', views.BookmarkListView.as_view(), name='bookmark_list'),
path('tags/', views.TagCloudView.as_view(), name='tag_cloud'),
]
#6. 수정사항을 push 해서 반영해주고 도메인/sitemap.xml
로 접속해보면 xml 사이트맵이 보이는 것을 확인할 수 있다.
그러나 잘 보면 사이트 주소가 example.com 으로 우리 홈페이지의 주소가 아닌 것을 볼 수 있는데, 이는 Django admin 에서 수정해 주어야 한다. Admin 화면으로 접속해 보면 'Sites' 항목 아래에 sites 가 있는것을 볼 수 있는데, 여기 들어가보면 site 이름이 example.com 으로 되어 있다.
이 부분을 클릭해서 원하는 도메인 이름으로 바꾸어 준다.
이후 사이트맵에 다시 접속해 보면 정상적으로 도메인이 변경되어 있는 것을 확인할 수 있다.
사이트맵을 작성해 놓으면 검색엔진이 크롤링하기가 수월해지고 그에 따라서 검색 결과에 사이트의 내용이 노출되는데도 도움이 되므로 가능하면 만들어 놓는 것이 좋겠다.