با خودکار کردن تجزیه و تحلیل و اعتبارسنجی داده های Logfile به سیستم برای سئو با استفاده از پایتون (با اسکریپت) در وقت و هزینه خود صرفه جویی کنید! داده های کرالر موتور جستجو که در Logfile وجود دارد، منبع خارق العاده ای از اطلاعات برای هر متخصص سئو است. با تجزیه و تحلیل Logfile ها به سیستم، می توانید درک دقیق نحوه خزیدن و تفسیر موتور های جستجو از وب سایت خود را بدست آورید. در این پست قصد داریم نحوه استفاده از پایتون برای تجزیه و تحلیل و بهینه سازی Logfile های سرور برای سئو را بررسی کنیم.
این کار به شما در مواردی کمک می کند:
- با ارائه شواهد غیر قابل انکار درباره نحوه رفتار موتور های جستجو، نظریه های خود را معتبر ارزیابی کنید.
- با کمک به شما در درک مقیاس یک مشکل و تأثیر احتمالی رفع آن، یافته های خود را در اولویت قرار دهید.
- موارد دیگری را که هنگام استفاده از سایر منابع داده قابل مشاهده نیستند، کشف کنید.
اما با وجود مزایای فراوان، داده های Logfile به اندازه مکرر مورد نیاز استفاده نمی شود. دلایل قابل درک است:
- دسترسی به داده ها معمولاً شامل یک تیم توسعه دهنده است که ممکن است زمان بر باشد.
- فایل های خام می توانند بزرگ باشند و در قالب های نامرسوم ارائه شوند، بنابراین تجزیه و تحلیل داده ها به تلاش نیاز دارد.
- ابزار هایی که برای سهولت کار فرآیند طراحی شده اند ممکن است نیاز به یکپارچه سازی داده ها قبل از انتقال داده ها به آن داشته باشند و هزینه های آن نیز بسیار زیاد است.
همه این مسائل موانع ورود کاملاً معتبری هستند، اما لزوماً قابل غلبه نیستند. با کمی دانش اساسی در زمینه کد نویسی، می توانید کل فرآیند را خودکار کنید. این دقیقاً همان کاری است که ما قصد داریم در این آموزش گام به گام استفاده از پایتون برای تجزیه و تحلیل Logfile های سرور برای سئو انجام دهیم. برای شروع نیز اسکریپتی خواهید یافت.
برای مطالعه بیشتر:
ملاحظات اولیه
یکی از بزرگ ترین چالش ها در تجزیه و تحلیل داده هایLogfile تعداد زیاد قالب های بالقوه است. Apache ،Nginx و IIS طیف وسیعی از گزینه های مختلف را ارائه می دهند و به کاربران این امکان را می دهند تا داده های برگشتی را سفارشی کنند.
برای پیچیدگی بیشتر مسائل، اکنون بسیاری از وب سایت ها از ارائه دهندگان CDN مانندCloudflare ، Cloudfront و Akamai برای ارائه مطالب از نزدیکترین مکان به کاربر استفاده می کنند. هر یک از این ها قالب های خاص خود را نیز دارد.
ما بر روی Format Log Combined برای این پست تمرکز خواهیم کرد، زیرا این حالت به صورت پیش فرض برای Nginx و گزینه ای معمول در سرور های Apache است.
اگر مطمئن نیستید با چه نوع قالبی روبرو هستید، سرویس هایی مانند Builtwith و Wappalyzer هر دو اطلاعات بسیار خوبی در مورد پشته فناوری وب سایت ارائه می دهند. اگر دسترسی مستقیم به یک ذینفع فنی نداشته باشید، می توانند در تعیین این موضوع به شما کمک کنند.
هنوز هیچیک بهتر نیست؟ یکی از فایل های خام را باز کنید. غالباً، نظرات با اطلاعات مربوط به زمینه های خاص ارائه می شوند، که می توانند پس از آن ارجاع داده شوند.
#Fields: time c-ip cs-method cs-uri-stem sc-status cs-version
17:42:15 172.16.255.255 GET /default.htm 200 HTTP/1.0
نکته دیگر این است که ما می خواهیم موتور های جستجو را در چه مواردی قرار دهیم، زیرا این امر باید در فیلتر کردن و اعتبار سنجی اولیه ما لحاظ شود.
شناسایی Logfile ها و تعیین فرمت ها
برای انجام تجزیه و تحلیل معنی دار سئو، حداقل 100 هزار درخواست و 2-4 هفته داده برای سایت متوسط می خواهیم. با توجه به اندازه فایل ها، گزارش ها معمولاً به روز های جداگانه تقسیم می شوند. تقریباً تضمین شده است که چندین فایل برای پردازش دریافت خواهید کرد.
از آنجا که نمی دانیم با چند فایل سر و کار داریم، مگر اینکه قبل از اجرای اسکریپت آن ها را با هم ترکیب کنیم، اولین قدم مهم ایجاد لیستی از تمام فایل های موجود در پوشه ما با استفاده از ماژول glob است. این به ما امکان می دهد هر فایلی را که مطابق با الگویی باشد که مشخص کنیم، برگردانیم. به عنوان مثال، کد زیر با هر فایل TXT مطابقت دارد.
import glob
files = glob.glob('*.txt')
Logfile ها را می توان در قالب های مختلف فایل ارائه کرد، البته نه فقط TXT.
در حقیقت، ممکن است گاهی اوقات پسوند فایل یکی از مواردی نباشد که شما تشخیص می دهید. در اینجا یک Logfile خام از سرویس تحویل ورود به سیستم Akamai وجود دارد، که این موضوع را به خوبی نشان می دهد:
bot_log_100011.esw3c_waf_S.202160250000-2000-41
بعلاوه، این امکان وجود دارد که فایل های دریافت شده در چندین زیر پوشه تقسیم شده باشد و ما نمی خواهیم وقت خود را برای کپی کردن آن ها در یک مکان واحد تلف کنیم.
خوشبختانه، glob از هر دو جستجوی بازگشتی و عملگر های wildcard پشتیبانی می کند. این بدان معنی است که ما می توانیم لیستی از تمام فایل های موجود در یک زیر پوشه یا زیر پوشه کودک ایجاد کنیم.
files = glob.glob('**/*.*', recursive=True)
در مرحله بعدی، می خواهیم انواع فایل ها را در لیست خود شناسایی کنیم. برای این کار می توان نوع MIME فایل خاص را تشخیص داد. این دقیقاً به ما می گوید که فارغ از پسوند، دقیقاً با چه نوع فایلی سروکار داریم.
با استفاده از python-magic، دور تا دور کتابخانه libmagic C و ایجاد عملکرد ساده می توان به این مهم دست یافت.
pip install python-magic
pip install libmagic
import magic
def file_type(file_path):
mime = magic.from_file(file_path, mime=True)
return mime
از درک لیست می توان برای جستجوی فایل های ما و اعمال عملکرد، ایجاد یک دیکشنری برای ذخیره نام و نوع استفاده کرد.
file_types = [file_type(file) for file in files]
file_dict = dict(zip(files, file_types))
سرانجام، یک تابع و یک حلقه while برای استخراج لیستی از فایل هایی که نوع متن / ساده MIME را برمی گردانند و موارد دیگر را حذف می کنند.
uncompressed = []
def file_identifier(file):
for key, value in file_dict.items():
if file in value:
uncompressed.append(key)
while file_identifier('text/plain'):
file_identifier('text/plain') in file_dict
استخراج درخواست موتور جستجو با استفاده از پایتون در Logfile
پس از فیلتر کردن فایل های موجود در پوشه (ها)، مرحله بعدی فیلتر کردن خود فایل ها فقط با استخراج درخواست هایی است که برای ما مهم است.
با این کار دیگر نیازی به ترکیب فایل ها با استفاده از ابزار های خط فرمان مانند GREP یا FINDSTR نیست، با جستجوی اجتناب ناپذیر 5-10 دقیقه ای از طریق برگه های باز نوت بوک و نشانک ها برای یافتن دستور صحیح صرفه جویی می شود.
در این حالت، چون ما فقط درخواست های Googlebot را می خواهیم، جستجوی “Googlebot” با همه عوامل کاربری مربوطه مطابقت دارد.
برای خواندن و نوشتن فایل خود و ماژول regex پایتون، RE، می توانیم از تابع open Python استفاده کنیم تا جستجو را انجام دهیم.
import re
pattern = 'Googlebot'
new_file = open('./googlebot.txt', 'w', encoding='utf8')
for txt_files in uncompressed:
with open(txt_files, 'r', encoding='utf8') as text_file:
for line in text_file:
if re.search(pattern, line):
new_file.write(line)
Regex این کار را با استفاده از یک عملگر OR به راحتی مقیاس پذیر می کند.
pattern = 'Googlebot|bingbot'
درخواست تجزیه با استفاده از پایتون در Logfile
در پست قبلی، هملت باتیستا راهنمایی در مورد نحوه استفاده از regex برای تجزیه درخواست ها ارائه داد.
به عنوان یک روش جایگزین، ما از تجزیه کننده CSV داخلی قدرتمند Pandas و برخی توابع اساسی پردازش داده استفاده خواهیم کرد:
- ستون های غیر ضروری را رها کنید.
- مهر زمان را قالب بندی کنید.
- یک ستون با URL کامل ایجاد کنید.
- تغییر نام و ترتیب مجدد ستون های باقیمانده.
به جای سخت گذاردن یک نام دامنه، از تابع ورودی می تواند برای درخواست کاربر استفاده کند و این را به عنوان یک متغیر ذخیره کند.
whole_url = input('Please enter full domain with protocol: ') # get domain from user input
df = pd.read_csv('./googlebot.txt', sep='\s+', error_bad_lines=False, header=None, low_memory=False) # import logs
df.drop([1, 2, 4], axis=1, inplace=True) # drop unwanted columns/characters
df[3] = df[3].str.replace('[', '') # split time stamp into two
df[['Date', 'Time']] = df[3].str.split(':', 1, expand=True)
df[['Request Type', 'URI', 'Protocol']] = df[5].str.split(' ', 2, expand=True) # split uri request into columns
df.drop([3, 5], axis=1, inplace=True)
df.rename(columns = {0:'IP', 6:'Status Code', 7:'Bytes', 8:'Referrer URL', 9:'User Agent'}, inplace=True) #rename columns
df['Full URL'] = whole_url + df['URI'] # concatenate domain name
df['Date'] = pd.to_datetime(df['Date']) # declare data types
df[['Status Code', 'Bytes']] = df[['Status Code', 'Bytes']].apply(pd.to_numeric)
df = df[['Date', 'Time', 'Request Type', 'Full URL', 'URI', 'Status Code', 'Protocol', 'Referrer URL', 'Bytes', 'User Agent', 'IP']] # reorder columns
تأیید درخواست ها با استفاده از پایتون در Logfile
تقلب در مورد عوامل کاربری موتور جستجو بسیار آسان است، و اعتبار سنجی درخواست را به یک قسمت حیاتی از فرآیند تبدیل می کند، مبادا با تجزیه و تحلیل خزنده های شخص ثالث خود، نتیجه گیری نادرست کنیم. برای این کار، ما می خواهیم یک کتابخانه به نام dnspython نصب کنیم و یک DNS معکوس انجام دهیم.
قبل از استفاده مجدد از نتایج و فیلتر کردن هر گونه درخواست نامعتبر، از Pandas می توان برای رها کردن IP های تکراری و جستجو در این DataFrame کوچک تر استفاده کرد.
from dns import resolver, reversename
def reverseDns(ip):
try:
return str(resolver.query(reversename.from_address(ip), 'PTR')[0])
except:
return 'N/A'
logs_filtered = df.drop_duplicates(['IP']).copy() # create DF with dupliate ips filtered for check
logs_filtered['DNS'] = logs_filtered['IP'].apply(reverseDns) # create DNS column with the reverse IP DNS result
logs_filtered = df.merge(logs_filtered[['IP', 'DNS']], how='left', on=['IP']) # merge DNS column to full logs matching IP
logs_filtered = logs_filtered[logs_filtered['DNS'].str.contains('googlebot.com')] # filter to verified Googlebot
logs_filtered.drop(['IP', 'DNS'], axis=1, inplace=True) # drop dns/ip columns
استفاده از این روش سرعت جستجوها را به شدت افزایش می دهد و میلیون ها درخواست را در چند دقیقه تأیید می کند. در مثال زیر، 4 میلیون پوند درخواست در 26 ثانیه پردازش شد.
دسته بندی داده ها با استفاده از پایتون در Logfile
پس از اعتبار سنجی، ما یک مجموعه داده تمیز و قالب بندی شده باقی مانده ایم و می توانیم برای تجزیه و تحلیل آسان تر داده های Logfile چرخش این داده ها را شروع کنیم و برای این کار هم از پایتون استفاده می کنیم.
در ابتدا، بیایید با چند تجمع ساده با استفاده از توابع groupby و agg Pandas برای انجام شمارش تعداد درخواست ها برای کد های وضعیت مختلف شروع کنیم.
status_code = logs_filtered.groupby('Status Code').agg('size')
برای تکرار نوع شمارش شما در اکسل، لازم به ذکر است که ما باید یک تابع جمع “اندازه” را تعیین کنیم، نه “شمارش”.
با استفاده از شمارش، عملکرد در همه ستون های DataFrame فراخوانی می شود و مقادیر null به طور متفاوتی اداره می شوند.
با بازنشانی شاخص، عناوین هر دو ستون بازیابی می شود و ستون دوم را می توان به چیزی معنی دار تر تغییر نام داد.
status_code = logs_filtered.groupby('Status Code').agg('size').sort_values(ascending=False).reset_index()
status_code.rename(columns={0:'# Requests'}, inplace=True)
برای دستکاری پیشرفته تر داده ها، جداول محوری Pandas دارای عملکردی قابل مقایسه با اکسل هستند و تجمع پیچیده را با یک خط کد خاص امکان پذیر می کند.
در ابتدایی ترین سطح، این تابع به یک DataFrame و شاخص مشخص نیاز دارد، یا در صورت نیاز به چند اندیس، ایندکس می شود، و مقادیر مربوطه را برمی گرداند.
pd.pivot_table(logs_filtered, index['Full URL'])
برای ویژگی بیشتر، می توان مقادیر مورد نیاز را اعلام کرد و با استفاده از پارامتر aggfunc اجتماع ها، مجموع، میانگین و غیره را اعمال کرد. همچنین لازم به ذکر است پارامتر ستون ها، که به ما امکان می دهد مقادیر را برای خروجی واضح تر به صورت افقی نمایش دهیم.
status_code_url = pd.pivot_table(logs_filtered, index=['Full URL'], columns=['Status Code'], aggfunc='size', fill_value=0)
در اینجا یک مثال کمی پیچیده تر وجود دارد، که به جای شمارش تعداد درخواست ها، تعداد URL های منحصر به فرد خزیده شده برای هر کاربر را در روز می شمارد.
user_agent_url = pd.pivot_table(logs_filtered, index=['User Agent'], values=['Full URL'], columns=['Date'], aggfunc=pd.Series.nunique, fill_value=0)
اگر هنوز با این روش دست و پنجه نرم می کنید، میتو را ببینید. به شما امکان می دهد هنگام استفاده از JupyterLab با یک رابط بصری در Jupyter ارتباط برقرار کنید، اما همچنان کد مربوطه را خارج می کند.
تعیین محدوده ها با استفاده از پایتون در Logfile
برای نقاط داده مانند بایت که به احتمال زیاد مقادیر عددی مختلفی دارند، جمع کردن داده ها منطقی است.
برای انجام این کار، می توانیم فواصل خود را در داخل یک لیست تعریف کنیم و سپس از تابع cut برای مرتب سازی مقادیر به سطل های زباله استفاده می کنیم، با تعیین np.inf برای گرفتن چیزی بالاتر از حداکثر مقدار اعلام شده.
byte_range = [0, 50000, 100000, 200000, 500000, 1000000, np.inf]
bytes_grouped_ranges = (logs_filtered.groupby(pd.cut(logs_filtered['Bytes'], bins=byte_range, precision=0))
.agg('size')
.reset_index()
)
bytes_grouped_ranges.rename(columns={0: '# Requests'}, inplace=True)
از علامت گذاری فاصله در داخل خروجی برای تعریف دامنه های دقیق استفاده می شود، به عنوان مثال:
(50000 100000)
براکت های گرد نشان دهنده زمانی است که یک عدد در آن لحاظ نشده و یک براکت مربعی نیز در هنگام قرار گرفتن نشان می دهد. بنابراین، در مثال بالا، سطل شامل نقاط داده با ارزش بین 50،001 تا 100،000 است.
خروجی گرفتن با استفاده از پایتون در Logfile
آخرین مرحله در فرآیند ما خروجی گرفتن اطلاعات Logfile و دسته بندی است. برای سهولت در تجزیه و تحلیل، خروج گرفتن از این مورد به یک فایل اکسل (XLSX) به جای CSV منطقی است. فایل های XLSX از چندین برگ پشتیبانی می کنند، به این معنی که تمام DataFrames را می توان در یک پرونده ترکیب کرد.
با استفاده از تعالی می توان به این مهم دست یافت. در این حالت، یک شی ExcelWriter نیز باید مشخص شود زیرا بیش از یک صفحه به همان کتاب کار اضافه شده است.
writer = pd.ExcelWriter('logs_export.xlsx', engine='xlsxwriter', datetime_format='dd/mm/yyyy', options={'strings_to_urls': False})
logs_filtered.to_excel(writer, sheet_name='Master', index=False)
pivot1.to_excel(writer, sheet_name='My pivot')
writer.save()
هنگام خروجی گرفتن تعداد زیادی دسته بندی، با ذخیره DataFrames و نام ورق ها در دیکشنری و استفاده از حلقه for، به ساده سازی موارد کمک می کند.
sheet_names = {
'Request Status Codes Per Day': status_code_date,
'URL Status Codes': status_code_url,
'User Agent Requests Per Day': user_agent_date,
'User Agent Requests Unique URLs': user_agent_url,
}
for sheet, name in sheet_names.items():
name.to_excel(writer, sheet_name=sheet)
آخرین عارضه این است که محدودیت اکسل در اکسل 1.048.576 است. ما در حال خروجی گرفتن از هر درخواست هستیم، بنابراین این امر می تواند در هنگام برخورد با نمونه های بزرگ مشکلاتی را ایجاد کند. از آنجا که فایل های CSV محدودیتی ندارند، می توان از دستور if استفاده کرد تا خروجی CSV را به عنوان یک نسخه جدید اضافه کند.
اگر طول فایل Logfile مقدار DataFrame بیشتر از 1،048،576 باشد، در عوض این به عنوان CSV خروجی گرفته می شود و از شکست اسکریپت جلوگیری می کند در حالی که همچنان دسته بندی ها را به یک خروجی واحد ترکیب می کند.
if len(logs_filtered) <= 1048576:
logs_filtered.to_excel(writer, sheet_name='Master', index=False)
else:
logs_filtered.to_csv('./logs_export.csv', index=False)
سخن آخر
اطلاعات اضافی که می توان از داده های Logfile دریافت کرد ارزش دارد که مدتی در آن سرمایه گذاری کنید. اگر به دلیل پیچیدگی های موجود از استفاده از این داده ها اجتناب کرده اید، امیدوارم که این پست شما را متقاعد کند که می توان بر این موارد غلبه کرد.
برای کسانی که به ابزاری علاقه مند هستند که به کد نویسی مرتبط می شود، امیدوارم با انجام این روند، درک بیشتری از ملاحظات مربوط به هنگام ایجاد یک اسکریپت بزرگتر برای خودکار کردن کار های تکراری و زمان بر، به شما داده شود.
این اسکریپت شامل موارد اضافی مانند GSC API یکپارچه سازی، دسته بندی های بیشتر، و پشتیبانی از دو قالب ورود به سیستم دیگر است: Amazon ELB و W3C (استفاده شده توسط IIS).
برای افزودن به یک قالب دیگر، نام را در لیست log_fomats در خط 17 قرار دهید و یک عبارت elif اضافی در خط 193 اضافه کنید (یا یکی از موارد موجود را ویرایش کنید).
برای دریافت اطلاعات بیشتر در مورد نحوه بهینه سازی فایل robot.txt نیز می توانید به مقاله مربوطه در همین وبلاگ مراجعه کنید.
منبع: searchenginejournal
دیدگاهی بنویسید