التعامل مع الملفات في بايثون: القراءة والكتابة
40 دقيقة تقريبًا
- Variable
- String
- Integer
- Float
- Boolean
- List
- Dictionary
- type
- key
- index
- append
- len
- if
- else
- elif
- Comparison Operators
- and
- or
- not
- for
- while
- break
- continue
- Function
- def
- Parameter
- Argument
- return
- set
- open
- with
- read
- write
- strip
يحسب العدّاد في الأعلى تمارين الدرس، وعددها 2، أما القراءة وتشغيل الأمثلة فلا تُحتسب.
في الدروس السابقة، كل البيانات اللي كنا بنشتغل عليها كنا بنكتبها جوه الكود بنفسنا.
مثلًا، لو عندنا مجموعة روابط:
['https://example.com/', 'https://example.com/blog/', 'https://example.com/services/']
وده كان مناسب جدًا وإحنا بنتعلم Lists وLoops وConditions، لأن عدد الروابط قليل وهدفنا كان نفهم بايثون نفسها.
لكن تخيل إنك شغال على موقع وطلعت من Screaming Frog مثلًا 5,000 رابط.
هل منطقي تعمل كده؟
طبعًا لا.
في الشغل الحقيقي، البيانات غالبًا هتكون موجودة في ملف، وبايثون هو اللي محتاج يروح للملف ده ويقرأ البيانات.
وده بالظبط اللي هنتعلمه في الدرس.
هنبدأ بملف نصي عادي جدًا، وبعد ما نفهم الفكرة كويس، هنستخدم نفس الأساس بعد كده مع ملفات أكبر وأهم بالنسبة للـ SEO مثل CSV.
أول مشكلة: إزاي بايثون يقرأ ملف؟
هنعمل ملف جديد اسمه urls.txt، ونكتب جواه الروابط دي:
وخلي ملف urls.txt موجود في نفس المجلد اللي موجود فيه ملف بايثون اللي بتشتغل عليه. يعني لو عندك lesson6.py، يبقى شكل المجلد:
دلوقتي عندنا البيانات، لكن بايثون لسه ميعرفش عنها أي حاجة.
لازم نقوله افتح الملف الأول. وده بنعمله باستخدام open(). خلينا نجرب أبسط مثال:
<_io.TextIOWrapper name='urls.txt' mode='r' encoding='utf-8'>
ممكن تبص على الناتج وتقول: أنا مستفيد إيه من الكلام ده؟
ولا حاجة تقريبًا لحد دلوقتي. إحنا فتحنا الملف فقط، لكن لسه مقريناش اللي جواه.
قبل ما نقرأه، خلينا نفهم السطر ده الأول: file = open("urls.txt", "r", encoding="utf-8")
الدالة open() وظيفتها إنها تفتح ملف علشان بايثون يقدر يتعامل معاه. وجواها كتبنا "urls.txt"، وده ببساطة اسم الملف اللي عايزين نفتحه.
بعده كتبنا "r"، والحرف r جاي من كلمة read. يعني إحنا بنقول لبايثون:
أما encoding="utf-8" فدي مهمة علشان بايثون يعرف يقرأ النص الموجود في الملف بشكل صحيح، وخصوصًا لما يكون عندك محتوى عربي.
ومش مطلوب منك دلوقتي تدخل في تفاصيل الـ Encoding، كل اللي محتاج تعرفه إننا هنستخدم utf-8 مع الملفات النصية علشان نتجنب مشاكل الأحرف.
بعد ما فتحنا الملف، حفظنا الملف المفتوح داخل متغير اسمه file. يعني بدل ما نفضل كل مرة نقول لبايثون افتح urls.txt، بقينا نقدر نتعامل معاه من خلال المتغير file.
لكن زي ما قلنا، إحنا فتحناه فقط. محتاجين نقرأ اللي جواه.
قراءة محتوى الملف
علشان نقرأ محتوى الملف، هنستخدم read(). نجرب:
https://example.com/ https://example.com/blog/python-seo/ https://example.com/services/seo/ https://example.com/blog/technical-seo/
كده بايثون فتح الملف فعلًا، وقرأ كل اللي جواه.
بص على السطر ده: content = file.read()
وبعدها print(content) طبعنا المحتوى.
طيب ليه كتبنا في الآخر file.close()؟ لأننا بعد ما فتحنا الملف وتعاملنا معاه، الأفضل نقفله لما نخلص. تقدر تعتبر إنك فتحت باب، خلصت اللي محتاجه، فقفلته.
لكن بما إننا لسه بنتعلم، فمش عايزك كل مرة تفضل مركز: أنا فتحت الملف، هل قفلته ولا لأ؟ بايثون عندها طريقة أفضل تخليك تفتح الملف وتتعامل معاه، وهي تتولى إغلاقه تلقائيًا. ودي الطريقة اللي هنستخدمها من هنا ورايح.
استخدام with
هنكتب نفس المثال بالشكل ده:
https://example.com/ https://example.com/blog/python-seo/ https://example.com/services/seo/ https://example.com/blog/technical-seo/
النتيجة هي هي. لكن لاحظ إننا محطناش file.close()، لأن with بتخلي بايثون يقفل الملف تلقائيًا بعد ما يخلص التعامل معاه.
خلينا نفهم السطر: with open("urls.txt", "r", encoding="utf-8") as file:
بعدها عندنا content = file.read(). وخلي بالك من الـ Indentation، السطر ده موجود جوه with. ولما الـ Indentation ينتهي، print(content) يبقى بايثون خلص التعامل مع الملف وقفله.
من هنا ورايح هنستخدم الطريقة دي with open(...) بدل الطريقة الأولى.
عندنا مشكلة جديدة
إحنا قدرنا نقرأ الملف كله مرة واحدة بـ content = file.read(). لكن في الـ SEO غالبًا مش ده اللي إحنا عايزينه.
إحنا عندنا ملف فيه أربع روابط، وإحنا مش عايزين الأربع روابط كنص واحد.
عايزين نمسك كل رابط لوحده. ليه؟ لأن بعد شوية ممكن نقول:
- لو الرابط فيه
/blog/اعمل حاجة. - لو الرابط فيه
/product/اعمل حاجة تانية. - افحص كل URL لوحده.
- احفظ مجموعة معينة من الروابط.
وهنا نقدر نستفيد من الـ for loop اللي اتعلمناها. نجرب:
https://example.com/ https://example.com/blog/python-seo/ https://example.com/services/seo/ https://example.com/blog/technical-seo/
ركز في حاجة غريبة. ليه فيه سطر فاضي بين كل URL والتاني؟
إحنا مقلناش لـ print() تعمل كده. المشكلة جاية من الملف نفسه.
كل URL موجود في سطر، يعني نهاية أول URL فيها انتقال للسطر الجديد. بايثون قرأت الانتقال ده مع النص. وبعدها print() نفسها بتنزل سطر جديد. فبقينا بننزل سطر مرتين.
إحنا محتاجين ننظف النص قبل ما نستخدمه. وهنا هنحتاج حاجة جديدة.
strip()
خلينا نبعد عن الملفات ثانية ونجربها على نص بسيط:
Python
كان عندنا مسافات قبل وبعد كلمة Python. لما استخدمنا strip() شالت المسافات الموجودة في البداية والنهاية.
ونفس الفكرة هتفيدنا مع السطر اللي جاي من الملف، لأنها هتشيل علامة الانتقال للسطر الجديد الموجودة في نهايته. نجرب:
https://example.com/ https://example.com/blog/python-seo/ https://example.com/services/seo/ https://example.com/blog/technical-seo/
كده النتيجة مظبوطة. خلينا نشوف اللي بيحصل واحدة واحدة.
عندنا for line in file:
في أول دورة من الـ Loop، المتغير line بيكون فيه أول سطر. إحنا بعد كده عملنا url = line.strip()، يعني نظفنا السطر وحفظنا النسخة النظيفة داخل url. وبعدها print(url) طبعنا الرابط. بعدين الـ Loop ترجع تاخد السطر اللي بعده. وهكذا لحد نهاية الملف.
كده لأول مرة بقينا بنتعامل مع كل URL بشكل مستقل. وده بالظبط اللي هنحتاجه في شغلنا.
نرجع لاستخدام الـ Lists
إحنا دلوقتي بنقرأ الروابط ونطبعها. لكن ممكن بدل ما أطبعها فقط، أحب أحطها في List علشان أستخدمها بعد كده. وده شيء إحنا بالفعل اتعلمناه. نبدأ بقائمة فاضية:
['https://example.com/', 'https://example.com/blog/python-seo/', 'https://example.com/services/seo/', 'https://example.com/blog/technical-seo/']
لاحظ هنا إننا مش بنتعلم بايثون من أول وجديد. إحنا بنركب الحاجات اللي اتعلمناها فوق بعض.
تعلمنا قبل كده إن urls = [] تعمل List فاضية. وتعلمنا إن append() تضيف عنصر للقائمة. فكل اللي عملناه دلوقتي إن العنصر مبقاش مكتوب بإيدنا داخل الكود. العنصر جاي من ملف. وده فرق مهم جدًا.
قبل كده إحنا اللي كتبنا البيانات. دلوقتي بايثون هي اللي بتجيب البيانات من بره البرنامج.
نبدأ نعمل حاجة تخص SEO
دلوقتي الملف عندنا فيه أربع روابط، وعايزين نطلع روابط المقالات فقط.
إحنا بالفعل اتعلمنا الـ if قبل كده. فممكن نقول:
/blog/ موجودة داخل الرابط، ضيف الرابط للقائمة.['https://example.com/blog/python-seo/', 'https://example.com/blog/technical-seo/']
ركز هنا لأن المثال ده مهم. تعالى نمشي مع بايثون بنفس ترتيب التنفيذ.
- 1بدأنا بقائمة فاضية
blog_urls. - 2فتحنا الملف، وأخدنا أول سطر:
https://example.com/ —هل فيه/blog/؟ لا، إذن مش هيتضاف. - 3الرابط اللي بعده:
https://example.com/blog/python-seo/ —هل فيه/blog/؟ نعم، إذن يتضاف للقائمة. - 4الرابط اللي بعده:
https://example.com/services/seo/ —مفيهوش/blog/، فمش هيتضاف. - 5الرابط الأخير:
https://example.com/blog/technical-seo/ —فيه/blog/، فيتضاف. - 6فالنتيجة النهائية فيها الرابطين اللي فيهم
/blog/فقط.
لحد هنا إحنا قدرنا ناخد ملف كامل، ونطلع منه فقط البيانات اللي محتاجينها.
لكن النتيجة لسه موجودة داخل بايثون. ماذا لو عايزين نحفظها؟
إزاي بايثون يكتب ملف؟
زي ما استخدمنا "r" للقراءة، عندنا "w" للكتابة. الحرف w جاي من write. نجرب مثال بسيط الأول:
لما تشغل الكود، بايثون هتنشئ ملف اسمه result.txt وجواه SEO Analysis Complete.
لكن زي ما اتفقنا، إحنا في الكورس مش عايزين نكتب كود ونفترض إن كل شيء حصل.
هنقرأ الملف بعدها ونطبع النتيجة:
SEO Analysis Complete
كده شفنا بعنينا إن بايثون كتبت النص فعلًا داخل الملف.
لكن لازم تعرف حاجة مهمة جدًا عن "w": لو الملف موجود أصلًا وداخله بيانات، استخدام w هيبدأ الكتابة من جديد.
يعني لو result.txt فيه Old Report وشغلنا الكود ده:
New Report
Old Report اختفت. إذن خليك فاكر:
rيعني اقرأ الملف.wيعني اكتب الملف من جديد.
وده معناه إنك لازم تكون واعي لما تستخدم w على ملف فيه بيانات مهمة.
نحفظ روابط الـ Blog
دلوقتي عندنا القائمة blog_urls وفيها رابطين. عايزين نخلي بايثون تعمل ملف اسمه blog_urls.txt وتكتب الروابط جواه. ممكن نعمل:
https://example.com/blog/python-seo/https://example.com/blog/technical-seo/
فيه مشكلة. الرابطين لازقين في بعض.
وده طبيعي، لأننا قلنا لبايثون file.write(url) اكتب الرابط. لكن مقلناش لها بعد ما تكتبيه انزلي سطر جديد. وهنا هنحتاج نتعلم حاجة صغيرة جدًا اسمها \n.
يعني إيه \n؟
خلينا نجربها بعيد عن الملفات:
SEO Python
يعني \n بتقول لبايثون: انزل سطر جديد. فبدل file.write(url) هنكتب file.write(url + "\n")، يعني اكتب الرابط، وبعده انزل سطر جديد. نجرب المثال كامل:
https://example.com/blog/python-seo/ https://example.com/blog/technical-seo/
كده بقى عندنا ملف منظم، كل URL موجود في سطر مستقل.
نجمع كل حاجة في تطبيق واحد
دلوقتي بدل ما ندخل البيانات بإيدنا، هنخلي العملية كاملة من أول الملف لحد النتيجة.
المطلوب من بايثون:
- تقرأ الملف.
- تمسك كل URL لوحده.
- تنظف الرابط.
- تختار روابط
/blog/فقط. - تحفظها في List.
- تنشئ ملف جديد فيه النتائج.
- تطبع النتائج علشان نشوف اللي حصل.
Blog URLs: https://example.com/blog/python-seo/ https://example.com/blog/technical-seo/
وفي نفس الوقت بايثون أنشأت ملف blog_urls.txt ومحتواه نفس الروابط، كل واحد في سطر.
عايزك تلاحظ هنا النقلة اللي حصلت. في أول الدروس كنا بنعمل:
- بيانات مكتوبة داخل الكود.
Pythonتتعامل معاها.print()
دلوقتي بقينا نعمل:
- ملف فيه بيانات.
Pythonتقرأه.Pythonتحلل البيانات.Pythonتختار اللي محتاجينه.Pythonتحفظ النتيجة في ملف جديد.
وده أقرب بكتير للطريقة اللي هنشتغل بيها فعلًا في الـ SEO.
طيب إيه الفرق بين w وa؟
في حاجة تانية صغيرة محتاجين نعرفها قبل ما نقفل موضوع الكتابة.
افترض إن عندك ملف اسمه report.txt وفيه Page 1. لو فتحناه باستخدام "w" وكتبنا Page 2، المحتوى القديم هيتشال.
لكن أحيانًا إحنا مش عايزين نستبدل الملف، إحنا عايزين نضيف حاجة في آخره. هنا بنستخدم "a"، والـ a جاية من append، بمعنى أضف إلى الموجود. نجرب:
Page 1 Page 2
في البداية استخدمنا "w" فأنشأنا الملف وكتبنا Page 1. بعدها استخدمنا "a" فبايثون احتفظت بالموجود وأضافت Page 2 في النهاية.
إذن الثلاثة اللي محتاج تعرفهم حاليًا:
rقراءة.wكتابة من جديد.aإضافة إلى الموجود.
مش محتاج تحفظ عشرات أوضاع فتح الملفات، التلاتة دول كفاية جدًا للمرحلة اللي إحنا فيها.
ملف موجود داخل Folder
لحد الآن ملف urls.txt موجود جنب ملف بايثون. لكن ممكن بعد كده تنظم مشروعك بالشكل ده:
هنا لو كتبت open("urls.txt") بايثون هتدور على الملف جنب lesson6.py. لكن هو مش هناك، هو جوه مجلد data. فلازم نقول مكانه:
https://example.com/ https://example.com/blog/python-seo/ https://example.com/services/seo/ https://example.com/blog/technical-seo/
الجزء data/urls.txt اسمه Path، يعني الطريق اللي بايثون هتمشي فيه علشان توصل للملف. دلوقتي مش محتاجين نتعمق أكتر من كده في موضوع الـ Paths، لأننا هنرجع له لما نحتاجه.
نستخدم Function اتعلمناها في الدرس السابق
إحنا في الدرس السابق اتعلمنا Functions.
فهل نقدر نخلي عندنا Function وظيفتها تقرأ روابط Blog من أي ملف؟ آه. نكتب:
['https://example.com/blog/python-seo/', 'https://example.com/blog/technical-seo/']
خلينا نفهم الجزء الجديد بالنسبة للمثال فقط.
عندنا get_blog_urls("urls.txt"). إحنا بنبعت للـ Function اسم الملف. فتستقبل filename، والقيمة هنا هتكون urls.txt. فلما بايثون توصل إلى with open(filename, ...) تقدر تعتبر إنها أصبحت with open("urls.txt", ...).
بعدها تعمل نفس اللي اتعلمناه: تقرأ كل سطر، تنظفه، تفحص هل فيه /blog/، تضيفه للقائمة. وفي النهاية return blog_urls ترجع القائمة.
مش الهدف هنا إننا نعقد موضوع الملفات بالـ Functions، الهدف إنك تبدأ تشوف إن الحاجات اللي اتعلمناها مش دروس منفصلة عن بعض. إحنا بدأنا نبني برنامج باستخدام أكثر من جزء من بايثون مع بعض.
تطبيق SEO أكبر
دلوقتي عندنا ملف urls.txt فيه ست روابط، وعايزين نقسم الروابط إلى Blog URLs وProduct URLs وOther URLs.
قبل ما تشوف الكود، فكر فيها بنفسك. إحنا محتاجين كام List؟
ثلاثة: blog_urls، product_urls، other_urls.
بعدها نقرأ كل URL. لو فيه /blog/ نضيفه إلى blog_urls. ولو فيه /product/ نضيفه إلى product_urls. ولو مش ده ولا ده، نحطه في other_urls.
Blog URLs: https://example.com/blog/seo/ https://example.com/blog/python/ Product URLs: https://example.com/product/laptop/ https://example.com/product/phone/ Other URLs: https://example.com/ https://example.com/about/
لاحظ إننا استخدمنا elif وelse اللي اتعلمناهم قبل كده. واستخدمنا \n المرة دي داخل print(): print("\nProduct URLs:") فهي بتنزل سطر قبل طباعة العنوان، علشان النتيجة تبقى أوضح.
نحفظ المجموعات الثلاث
دلوقتي مش عايزين النتائج تظهر في الشاشة فقط. عايزين ثلاث ملفات منفصلة، فنضيف:
ويبقى البرنامج كامل:
Blog URLs: https://example.com/blog/seo/ https://example.com/blog/python/ Product URLs: https://example.com/product/laptop/ https://example.com/product/phone/ Other URLs: https://example.com/ https://example.com/about/
وفي المجلد هتلاقي أربع ملفات: urls.txt وblog_urls.txt وproduct_urls.txt وother_urls.txt.
أنت هنا عملت برنامج صغير فعلًا. استقبل بيانات من ملف، حللها حسب شروط أنت محددها، قسمها، وبعدها حفظ النتائج في ملفات جديدة.
إيه اللي محتاج تكون فاهمه من الدرس؟
مش المطلوب إنك تحفظ الكود كامل. المهم تكون فاهم العلاقة.
لما يكون عندك ملف وعايز تقرأه: with open("urls.txt", "r", encoding="utf-8") as file:
لو عايز تقرأ كل المحتوى مرة واحدة: content = file.read()
لو عايز تتعامل مع كل سطر لوحده: for line in file:
لو السطر فيه مسافات أو علامة نزول سطر وعايز تنظفه: line.strip()
لو عايز تكتب ملف جديد: with open("result.txt", "w", encoding="utf-8") as file:
ولو عايز تضيف على ملف موجود بدل ما تستبدله: with open("result.txt", "a", encoding="utf-8") as file:
ولما تكتب أكتر من قيمة وكل واحدة المفروض تكون في سطر: file.write(url + "\n")
دي الأدوات الأساسية اللي محتاجها من الدرس.
اختبار عملي
pages.txt جاهز ليك — الاختبار بيشغّل كودك على نفس المحتوى اللي هيتقالك. الناتج مخفي لحد ما تحل، وتقدر تطلب تلميح بعد أول محاولة، والحل الكامل بيظهر بعد محاولتين.هنعمل الاختبار المرة دي على ملف حقيقي. أنشئ ملف pages.txt واكتب جواه:
السؤال الأول
طلّع روابط المنتجات من ملف
اكتب برنامج يفتح pages.txt، يقرأ كل رابط لوحده وينظفه بـ strip()، وينشئ قائمة اسمها product_urls تضم فقط الروابط اللي فيها /product/. اطبع كل رابط في القائمة في سطر مستقل، ثم أنشئ ملفًا جديدًا اسمه product_urls.txt واحفظ فيه نفس الروابط، كل رابط في سطر مستقل.
السؤال الثاني
قسّم الملف إلى ثلاث مجموعات
عدّل الحل اللي فوق بحيث يقسم pages.txt إلى ثلاث مجموعات: Blog وProduct وOther، ويحفظ كل مجموعة في ملف منفصل: blog_urls.txt وproduct_urls.txt وother_urls.txt.
لو قدرت تعمل الجزء ده بنفسك، فأنت مش بس فهمت Files، أنت بدأت تربط Files مع Lists وLoops وConditions، ودي الفكرة الأساسية اللي محتاجين نوصل لها قبل ما نبدأ نتعامل مع بيانات SEO أكبر في الدروس القادمة.
بقيت تمارين لم تحلّها
0/2التمارين المتبقية: 2 من 2. يُحتسب الدرس مكتملًا حين تحلّها كلها، ويمكنك العودة إليها متى شئت.
أحسنت، وصلت إلى نهاية الدرس.