أتمتة تقارير الأداء الأسبوعية عبر إرسال بيانات السيو إلى Discord و Slack
أتمتة تقارير الأداء الأسبوعية عبر إرسال بيانات السيو إلى Discord و Slack
تُعد أتمتة تقارير الأداء الأسبوعية عبر إرسال بيانات السيو إلى Discord و Slack حلاً ثورياً للمسوقين الرقميين وأخصائيي تحسين محركات البحث (SEO) الذين يجدون أنفسهم غارقين في المهام الروتينية المتكررة. في عالم التسويق الرقمي سريع التطور، يُعد الوقت مورداً ثميناً، وغالباً ما تُهدر ساعات طويلة في تجميع البيانات يدوياً من أدوات مثل Google Search Console، وتنسيقها، ثم مشاركتها مع الفريق. هذه العملية لا تستنزف الوقت فحسب، بل تزيد أيضاً من احتمالية الأخطاء البشرية وتؤخر الحصول على رؤى قيمة. تخيل أن تتلقى تقريراً مفصلاً بأداء موقعك في محركات البحث كل صباح اثنين، مباشرة في قناتك المفضلة على Discord أو Slack، دون أي تدخل يدوي منك. هذا المقال سيأخذك في رحلة تفصيلية خطوة بخطوة لتحقيق هذا الهدف، باستخدام قوة لغة البرمجة Python وواجهات برمجة التطبيقات (APIs) المختلفة.
لماذا أتمتة تقارير السيو الأسبوعية؟
تتجاوز فوائد أتمتة تقارير السيو مجرد توفير الوقت، فهي تمثل نقلة نوعية في كيفية إدارة وتتبع أداء المواقع:
- توفير الوقت والجهد: بدلاً من قضاء ساعات في استخراج البيانات وتنسيقها، يمكن للسكريبت أن يقوم بذلك في دقائق، مما يتيح لك التركيز على مهام أكثر استراتيجية.
- الدقة والاتساق: تقلل الأتمتة من الأخطاء البشرية وتضمن أن تكون التقارير متسقة في شكلها ومحتواها أسبوعياً.
- رؤى فورية وقابلة للتنفيذ: وصول سريع إلى البيانات يعني اتخاذ قرارات أسرع بناءً على أحدث المعلومات، مما يساعد في تعديل الاستراتيجيات بسرعة.
- تحسين التعاون الجماعي: إرسال التقارير مباشرة إلى قنوات الاتصال الجماعية مثل
DiscordوSlackيضمن أن يكون جميع أعضاء الفريق على اطلاع دائم بأداء السيو، مما يعزز الشفافية والتعاون. - التركيز على التحليل: بدلاً من جمع البيانات، يصبح بإمكانك قضاء وقت أطول في تحليلها وفهم دلالاتها، مما يؤدي إلى تحسينات حقيقية في الأداء.
الأدوات والمكونات الأساسية
لتحقيق هذا المشروع، سنحتاج إلى مجموعة من الأدوات والتقنيات:
Python 3.x: لغة البرمجة التي سنستخدمها لكتابة السكريبت.- Google Search Console API: الواجهة التي تسمح لنا باستخراج بيانات السيو برمجياً.
Discord Webhooks: طريقة لإرسال رسائل آلية إلى قنواتDiscord.Slack Webhooks: طريقة لإرسال رسائل آلية إلى قنواتSlack.- المكتبات البرمجية في
Python:google-api-python-clientوoauth2clientللمصادقة والتفاعل معGoogle APIs.requestsلإرسال طلباتHTTP POSTإلىwebhooks.pandasلمعالجة وتنسيق البيانات.
الخطوات العملية لأتمتة التقارير
1. إعداد مشروع Google Cloud Platform و Search Console API
للوصول إلى بيانات Google Search Console برمجياً، ستحتاج إلى إعداد مشروع في Google Cloud Platform (GCP) وإنشاء حساب خدمة.
- إنشاء مشروع
GCP: اذهب إلى Google Cloud Console وأنشئ مشروعاً جديداً. - تفعيل
Search Console API: من لوحة تحكم المشروع، ابحث عن “Google Search Console API” وقم بتفعيله. - إنشاء حساب خدمة (
Service Account):- من قائمة التنقل، اختر “
IAM & Admin” ثم “Service Accounts“. - انقر على “
CREATE SERVICE ACCOUNT“، أعطه اسماً ووصفاً. - في الخطوة الثانية، امنحه دور “
Project > Viewer” أو دوراً أكثر تحديداً إذا كنت تفضل. - في الخطوة الثالثة، أنشئ مفتاحاً جديداً من نوع
JSONوقم بتنزيله. احتفظ بهذا الملف بأمان، حيث يحتوي على بيانات اعتماد حساب الخدمة الخاص بك.
- من قائمة التنقل، اختر “
- منح حساب الخدمة حق الوصول إلى
Google Search Console:- انسخ عنوان البريد الإلكتروني لحساب الخدمة (الذي ينتهي بـ
@developer.gserviceaccount.com). - اذهب إلى
Google Search Consoleالخاص بموقعك، اختر “Settings” ثم “Users and permissions“. - انقر على “
Add user“، الصق عنوان البريد الإلكتروني لحساب الخدمة، وامنحه إذن “Full” (كامل) للوصول إلى بيانات الموقع.
- انسخ عنوان البريد الإلكتروني لحساب الخدمة (الذي ينتهي بـ
2. إعداد Webhooks في Discord و Slack
تُعد Webhooks الطريقة الأسهل لإرسال رسائل آلية إلى قنوات Discord و Slack.
- لـ
Discord:- افتح خادم
Discordالخاص بك، اذهب إلى “Server Settings” ثم “Integrations“. - انقر على “
Create Webhook“، ثم قم بتخصيص الاسم والقناة التي سيتم إرسال الرسائل إليها. - انسخ
Webhook URLالذي يظهر لك.
- افتح خادم
- لـ
Slack:- اذهب إلى Slack API وقم بإنشاء تطبيق جديد أو اختر تطبيقاً موجوداً.
- من قائمة التطبيق، اختر “
Incoming Webhooks” وقم بتفعيله. - انقر على “
Add New Webhook to Workspace“، واختر القناة التي تريد إرسال الرسائل إليها. - انسخ
Webhook URLالذي يظهر لك.
Webhook URLs في مكان آمن، ولا تشاركها علناً، حيث يمكن لأي شخص لديه هذا الرابط إرسال رسائل إلى قناتك.3. كتابة كود Python لاستخراج البيانات
الآن، لنبدأ بكتابة كود Python. تأكد من تثبيت المكتبات المطلوبة أولاً:
pip install google-api-python-client oauth2client requests pandas
هذا هو الجزء الأساسي من السكريبت الذي يستخرج البيانات من Google Search Console:
import os
from datetime import datetime, timedelta
import json
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
import requests
# --- Configuration --- #
KEY_FILE_LOCATION = 'path/to/your/service_account_key.json' # Replace with your JSON key file path
SITE_URL = 'https://www.your-website.com/' # Replace with your website URL in GSC format
DISCORD_WEBHOOK_URL = 'YOUR_DISCORD_WEBHOOK_URL' # Replace with your Discord Webhook URL
SLACK_WEBHOOK_URL = 'YOUR_SLACK_WEBHOOK_URL' # Replace with your Slack Webhook URL
# --- Google Search Console API Authentication --- #
def get_service_account_credentials():
scope = ['https://www.googleapis.com/auth/webmasters.readonly']
return ServiceAccountCredentials.from_json_keyfile_name(KEY_FILE_LOCATION, scope)
def get_search_console_service():
credentials = get_service_account_credentials()
return build('webmasters', 'v3', credentials=credentials)
# --- Data Extraction from GSC --- #
def get_search_console_data(service, site_url, start_date, end_date, dimensions=None, row_limit=50):
if dimensions is None:
dimensions = ['query'] # Default to query dimension
request_body = {
'startDate': start_date.strftime('%Y-%m-%d'),
'endDate': end_date.strftime('%Y-%m-%d'),
'dimensions': dimensions,
'rowLimit': row_limit
}
try:
response = service.searchanalytics().query(
siteUrl=site_url,
body=request_body
).execute()
return response.get('rows', [])
except Exception as e:
print(f"Error fetching data from GSC: {e}")
return []
# --- Main Script Logic --- #
if __name__ == '__main__':
# Calculate dates for the last week (Sunday to Saturday)
today = datetime.now()
# Find the last Saturday (end of last week)
last_saturday = today - timedelta(days=(today.weekday() + 2) % 7) # +2 for Sunday, +1 for Monday, etc.
# Find the Sunday before last Saturday (start of last week)
last_sunday = last_saturday - timedelta(days=6)
start_date = last_sunday
end_date = last_saturday
print(f"Fetching data for the week: {start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}")
service = get_search_console_service()
# Get top 10 queries
queries_data = get_search_console_data(service, SITE_URL, start_date, end_date, dimensions=['query'], row_limit=10)
queries_df = pd.DataFrame(queries_data)
if not queries_df.empty:
queries_df.columns = ['Query', 'Clicks', 'Impressions', 'CTR', 'Position']
queries_df['CTR'] = queries_df['CTR'].apply(lambda x: f"{x:.2%}")
queries_df['Position'] = queries_df['Position'].apply(lambda x: f"{x:.2f}")
# Get top 10 pages
pages_data = get_search_console_data(service, SITE_URL, start_date, end_date, dimensions=['page'], row_limit=10)
pages_df = pd.DataFrame(pages_data)
if not pages_df.empty:
pages_df.columns = ['Page', 'Clicks', 'Impressions', 'CTR', 'Position']
pages_df['CTR'] = pages_df['CTR'].apply(lambda x: f"{x:.2%}")
pages_df['Position'] = pages_df['Position'].apply(lambda x: f"{x:.2f}")
# Get overall site data (no dimensions)
overall_data = get_search_console_data(service, SITE_URL, start_date, end_date, dimensions=[], row_limit=1)
overall_df = pd.DataFrame(overall_data)
if not overall_df.empty:
overall_df.columns = ['Clicks', 'Impressions', 'CTR', 'Position']
overall_df['CTR'] = overall_df['CTR'].apply(lambda x: f"{x:.2%}")
overall_df['Position'] = overall_df['Position'].apply(lambda x: f"{x:.2f}")
# ... (rest of the code for sending to Discord/Slack will go here)
'path/to/your/service_account_key.json' بمسار ملف مفتاح JSON الذي قمت بتنزيله، و 'https://www.your-website.com/' بعنوان URL لموقعك كما هو مسجل في Google Search Console.4. تنسيق البيانات وإرسالها إلى Discord
لإرسال البيانات إلى Discord، سنستخدم ميزة الـ embeds التي تسمح بتنسيق الرسائل بشكل جذاب.
# --- Discord Integration --- #
def send_to_discord(webhook_url, content, embeds=None):
headers = {'Content-Type': 'application/json'}
payload = {'content': content}
if embeds:
payload['embeds'] = embeds
try:
response = requests.post(webhook_url, data=json.dumps(payload), headers=headers)
response.raise_for_status() # Raise an exception for HTTP errors
print("Report sent to Discord successfully!")
except requests.exceptions.RequestException as e:
print(f"Error sending report to Discord: {e}")
# ... (inside if __name__ == '__main__': block, after data extraction)
discord_embeds = []
# Overall Data Embed
if not overall_df.empty:
overall_data_row = overall_df.iloc[0]
discord_embeds.append({
"title": f"تقرير أداء السيو الأسبوعي ({start_date.strftime('%Y-%m-%d')} - {end_date.strftime('%Y-%m-%d')})",
"description": f"ملخص الأداء العام للموقع {SITE_URL}",
"color": 3447003, # Blue color
"fields": [
{"name": "النقرات", "value": str(overall_data_row['Clicks']), "inline": True},
{"name": "مرات الظهور", "value": str(overall_data_row['Impressions']), "inline": True},
{"name": "متوسط نسبة النقر (CTR)", "value": str(overall_data_row['CTR']), "inline": True},
{"name": "متوسط الموضع", "value": str(overall_data_row['Position']), "inline": True}
]
})
# Top Queries Embed
if not queries_df.empty:
query_fields = []
for index, row in queries_df.iterrows():
query_fields.append({
"name": f"{index+1}. {row['Query']}",
"value": f"نقرات: {row['Clicks']}, ظهور: {row['Impressions']}, CTR: {row['CTR']}, موضع: {row['Position']}",
"inline": False
})
discord_embeds.append({
"title": "أهم 10 استعلامات بحث",
"description": "الاستعلامات التي جلبت أكبر عدد من النقرات",
"color": 15844367, # Yellow color
"fields": query_fields
})
# Top Pages Embed
if not pages_df.empty:
page_fields = []
for index, row in pages_df.iterrows():
page_fields.append({
"name": f"{index+1}. {row['Page'].split('//')[1].split('/')[0] + '/...' if len(row['Page']) > 50 else row['Page']}", # Shorten URL for display
"value": f"نقرات: {row['Clicks']}, ظهور: {row['Impressions']}, CTR: {row['CTR']}, موضع: {row['Position']}",
"inline": False
})
discord_embeds.append({
"title": "أهم 10 صفحات أداءً",
"description": "الصفحات التي جلبت أكبر عدد من النقرات",
"color": 5763719, # Green color
"fields": page_fields
})
send_to_discord(DISCORD_WEBHOOK_URL, "", embeds=discord_embeds)
5. تنسيق البيانات وإرسالها إلى Slack
بالنسبة لـ Slack، سنستخدم blocks و attachments لتنسيق الرسالة.
# --- Slack Integration --- #
def send_to_slack(webhook_url, blocks=None, attachments=None):
headers = {'Content-Type': 'application/json'}
payload = {}
if blocks:
payload['blocks'] = blocks
if attachments:
payload['attachments'] = attachments
try:
response = requests.post(webhook_url, data=json.dumps(payload), headers=headers)
response.raise_for_status() # Raise an exception for HTTP errors
print("Report sent to Slack successfully!")
except requests.exceptions.RequestException as e:
print(f"Error sending report to Slack: {e}")
# ... (inside if __name__ == '__main__': block, after Discord sending logic)
slack_blocks = []
slack_attachments = []
# Overall Data Block
if not overall_df.empty:
overall_data_row = overall_df.iloc[0]
slack_blocks.append({
"type": "header",
"text": {"type": "plain_text", "text": f"تقرير أداء السيو الأسبوعي ({start_date.strftime('%Y-%m-%d')} - {end_date.strftime('%Y-%m-%d')})"}
})
slack_blocks.append({
"type": "section",
"text": {"type": "mrkdwn", "text": f"*ملخص الأداء العام للموقع {SITE_URL}*"}
})
slack_blocks.append({
"type": "section",
"fields": [
{"type": "mrkdwn", "text": f"*النقرات:*\n{overall_data_row['Clicks']}"},
{"type": "mrkdwn", "text": f"*مرات الظهور:*\n{overall_data_row['Impressions']}"},
{"type": "mrkdwn", "text": f"*متوسط نسبة النقر (CTR):*\n{overall_data_row['CTR']}"},
{"type": "mrkdwn", "text": f"*متوسط الموضع:*\n{overall_data_row['Position']}"}
]
})
slack_blocks.append({"type": "divider"})
# Top Queries Attachment
if not queries_df.empty:
query_text = ""
for index, row in queries_df.iterrows():
query_text += f"{index+1}. *{row['Query']}*\nنقرات: {row['Clicks']}, ظهور: {row['Impressions']}, CTR: {row['CTR']}, موضع: {row['Position']}\n"
slack_attachments.append({
"color": "#F9A825", # Yellow color
"blocks": [
{"type": "section", "text": {"type": "mrkdwn", "text": "*أهم 10 استعلامات بحث*"}},
{"type": "section", "text": {"type": "mrkdwn", "text": query_text}}
]
})
# Top Pages Attachment
if not pages_df.empty:
page_text = ""
for index, row in pages_df.iterrows():
page_text += f"{index+1}. *{row['Page'].split('//')[1].split('/')[0] + '/...' if len(row['Page']) > 50 else row['Page']}*\nنقرات: {row['Clicks']}, ظهور: {row['Impressions']}, CTR: {row['CTR']}, موضع: {row['Position']}\n"
slack_attachments.append({
"color": "#36A64F", # Green color
"blocks": [
{"type": "section", "text": {"type": "mrkdwn", "text": "*أهم 10 صفحات أداءً*"}},
{"type": "section", "text": {"type": "mrkdwn", "text": page_text}}
]
})
send_to_slack(SLACK_WEBHOOK_URL, blocks=slack_blocks, attachments=slack_attachments)
Discord embeds و Slack blocks/attachments لتناسب هوية علامتك التجارية أو تفضيلات فريقك.6. جدولة السكريبت (Cron Job أو Task Scheduler)
لجعل هذه العملية مؤتمتة بالكامل، تحتاج إلى جدولة تشغيل السكريبت بانتظام. الطريقة الأكثر شيوعاً هي استخدام cron job على أنظمة Linux و macOS، أو Task Scheduler على Windows.
- على
Linux/macOS(باستخدامcron):افتح محرر
cronباستخدام الأمرcrontab -eوأضف السطر التالي لتشغيل السكريبت كل يوم أحد في الساعة 9 صباحاً (على سبيل المثال):0 9 * * 0 /usr/bin/python3 /path/to/your/script.pyتأكد من استبدال
/usr/bin/python3بالمسار الصحيح لمفسرPythonالخاص بك و/path/to/your/script.pyبالمسار الكامل لملف السكريبت. - على
Windows(باستخدامTask Scheduler):ابحث عن “
Task Scheduler” في قائمة ابدأ. أنشئ مهمة جديدة، وحدد وقت التشغيل (مثلاً، كل يوم أحد صباحاً)، ثم حدد الإجراء لتشغيل ملفPythonالخاص بك باستخدام مفسرPython.
تحسينات وميزات إضافية
يمكن توسيع هذا السكريبت ليشمل ميزات أكثر تقدماً:
- معالجة الأخطاء المحسّنة: إضافة المزيد من كتل
try-exceptللتعامل مع الأخطاء المحتملة في الشبكة أوAPI. - نطاقات التاريخ الديناميكية: يمكن تعديل السكريبت ليسمح بتحديد نطاقات تاريخ مخصصة، أو مقارنة الأداء بالأسبوع السابق.
- أبعاد إضافية: استخراج بيانات لأبعاد أخرى مثل الأجهزة، البلدان، أو أنواع البحث (صور، فيديو، أخبار).
- تحليل البيانات المتقدم: دمج مكتبات مثل
MatplotlibأوSeabornلإنشاء رسوم بيانية بسيطة للاتجاهات وإرسالها كصور مع التقرير. - تخزين البيانات: حفظ البيانات المستخرجة في قاعدة بيانات أو ملف
CSVللمراجعة المستقبلية أو التحليل التاريخي.
الخلاصة
إن أتمتة تقارير السيو الأسبوعية ليست مجرد رفاهية، بل هي ضرورة في بيئة التسويق الرقمي التنافسية اليوم. من خلال استثمار القليل من الوقت في إعداد هذا السكريبت، ستوفر ساعات لا تحصى على المدى الطويل، وستضمن حصول فريقك على رؤى دقيقة وفي الوقت المناسب. سواء كنت تدير موقعاً واحداً أو عشرات المواقع، فإن هذه الأتمتة ستمكنك من التركيز على ما يهم حقاً: تحليل البيانات واتخاذ قرارات استراتيجية لتحسين أداء موقعك في محركات البحث. ابدأ اليوم، وشاهد كيف يمكن للتكنولوجيا أن تحول روتينك اليومي.
الأسئلة الشائعة (FAQ)
- س1: هل أحتاج إلى خبرة برمجية عميقة لتطبيق هذا؟
- ج1: لا تحتاج إلى أن تكون مطور برمجيات محترفاً، ولكن معرفة أساسية بـ
Pythonوكيفية التعامل مع سطر الأوامر ستكون مفيدة جداً. الكود المقدم هنا مصمم ليكون واضحاً ومباشراً، ويمكنك تعديله بناءً على احتياجاتك. - س2: ما هي تكلفة استخدام Google Search Console API؟
- ج2: استخدام
Google Search Console APIمجاني تماماً. ومع ذلك، قد تكون هناك تكاليف مرتبطة بخدماتGoogle Cloud Platformالأخرى إذا قررت دمجها، لكن للوصول إلى بياناتSearch Console، لا توجد رسوم مباشرة. - س3: هل يمكنني تخصيص شكل التقرير؟
- ج3: نعم، الكود يوفر مرونة كبيرة لتخصيص شكل التقرير. يمكنك تعديل محتوى الـ
embedsفيDiscordأو الـblocksوattachmentsفيSlackلإضافة المزيد من البيانات، تغيير الألوان، أو إعادة ترتيب المعلومات لتناسب تفضيلات فريقك.