Python Web Scraping — ওয়েব স্ক্রেপিং
this article is from udemy course Modern web scraping with python using scrapy splash selenium
by Ahmed Rafik
Content
- 1. Scrapy Fundamental
- 2. XPath expressions and CSS selector Query
- 3. Project 1 : Spiders from A to Z
- 4. Project 2 : Dealing with Multiple pages
1. Scrapy
- installation process
- create a new project
web scraping হচ্ছে ওয়েব পেজ থেকে ডাটা extract করা । ডাটা হতে পারে text, images, videos, email etc.
আর Scrapy হচ্ছে একটি framework যেটা দিয়ে ওয়েব স্ক্রেপিং করা হয় ।
আমরা beautyful soup html parsars ব্যাবহার করে Requests লাইব্রেরী দিয়ে ওয়েব স্ক্রেপিং করতে পারি কিন্তু সেটা দিয়ে কমপ্লেক্স প্রজেক্ট করা যায় না, শুধুমাত্র সিঙ্গেল পেজ স্ক্র্যাপ করার জন্য beautyful soup ব্যাবহার করা যায় । তাই কমপ্লেক্স প্রজেক্টের জন্য scrapy ব্যাবহার করা হয় । scrapy দিয়ে একাধিক পেজ স্ক্র্যাপ করা যায়, almost ১০০০ পেজ প্রতিমিনিটে একসাথে স্ক্র্যাপ করা যায় CPU এর পারফরমেন্সের উপর ভিত্তি করে ।
scrapy তে সাধারণত ৫ টি কম্পোনেন্ট থাকে ।
- Spiders
- Pipelines
- Middlewares
- Engine
- Scheduler
Spiders : spider component হচ্ছে যেখানে আমাদের বলে দিতে হয় আমরা কি এক্সট্রাক্ট করতে চাচ্ছি ওয়েব পেজ থেকে ।প্রকৃতপক্ষে একটি scrapy তে অনেকগুলো spider থাকে । যেমনঃ scrapy.Spider, CrawlSpider, XMLFeedSpider ( xml ফাইল ফিড করার জন্য ), CSVFeedSpider (csv ফাইল ফিড করার জন্য ), sitemapSpider. তবে এদের মধ্যে অধিকাংশ সময় scrapy.Spider এবং CrawlSpider ব্যাবহার করা হয় ।
Pipelines : pipelines হচ্ছে মূলত আমরা যে ডাটা গুলো এক্সট্রাক্ট করি সেই ডাটা রিলেটেড । উদাহারন সরূপ আমরা যদি ডাটাগুলোকে cleaning/remove duplication/ storing data into external database সেসকল ক্ষেত্রে এই pipelines ব্যাবহার করতে হয় ।
Middlewares : middlewares হচ্ছে কোন ওয়েবসাইটে রিকোয়েস্ট পাঠানো অথবা রিসিভ করা । উদাহারন হিসেবে customer header এ কোন কিছু ইঞ্জেক্ট করা অথবা প্রক্সি পাঠানো ।
Engine : Engine এর কাজ হচ্ছে সকল কম্পোনেন্টের মধ্যে সমন্বয় সাধন করা ।
Scheduler : এটার কাজ হচ্ছে উপড়ের যে কাজ গুলো হচ্ছে সেগুলোর অর্ডার ঠিক রাখা এবং সে কাজ গুলো করে একটি queue মেইন্টেইন করে FIFO (First In First Out) order এ ।
উপড়ের এই কম্পোনেন্ট গুলোর কার্যপ্রণালীঃ
ধরা যাক আমরা quotes.com থেকে সকল quote গুলো স্ক্র্যাপ করতে চাচ্ছি ।
এখন প্রথমে spider থেকে engine এ রিকোয়েস্ট ট্রান্সফার হবে এরপর সেটা scheduler এ ত্রান্সমিট হবে । এই scheduler থেকে রিকোয়েস্ট পুনরায় engine এ ট্রান্সফার হয় । এরপর সেই রিকোয়েস্ট টি middleware এ পাঠিয়ে দেয় সেটা হেন্ডেল করে downloader Middleware. এখন সেখান থেকে রেসপন্স এলে সেটা engine এর মাধ্যমে spider এ পাঠিয়ে দেয় সেটা আবার হেন্ডেল করে spider middleware এটা ডাটা extract করার জন্য ব্যাবহার করা হয় । এখন সেই ডাটাগুলো engine হয়ে pipeline এ চলে যায় । এখান থেকেই ডাটা ক্লিনিং করা হয়, ডাটাবেজে সেভ করা হয় ।
বেশিরভাগ ওয়েবসাইটের রুট ডিরেক্টরিতে robots.txt নামে ফাইল থাকে এখানে ৩ টা জিনিস থাকে ।
- User-Agent : এটা হচ্ছে মূলত spider এর identity
- Allow : ঐ ইউজারকে scrape করতে allow করে
- Disallow : স্ক্র্যাপ করতে দিবে না ।
যেমন : www.facebook.com/robots.txt
installation process
create virtual environment
python3 -m venv env
এরপর নিচের কমান্ড দিয়ে কিছু প্যাকেজ ইন্সটল করি ।
pip3 install scrapy pylint autopep8
এরপর ইন্সটল করা এপ এর নামগুলো requirements.txt ফাইলে সেভ করার জন্য নিচের কমান্ডটি দিতে হয় ।
pip3 freeze > requirements.txt
scrapy কমান্ড দিলে সকল এভেইলেবল কমান্ড দেখা যায় ।
প্রথমে scrapy bench কমান্ড দিলে দেখা যায় কতো ফাস্ট কোন সাইট স্ক্র্যাপ করে আমার মেশিনে ।
এরপর fetch কমান্ড, এই কমান্ড দিয়ে কোন সাইটের full স্ট্রাকচার ডাউনলোড করা যায় ।
যেমনঃ
scrapy fetch http://google.com
এরপর genspider হচ্ছে এটা নতুন একটি spider তৈরি করে যেটা কিনা আগে থেকেই কিছু টেম্পলেটের মাধ্যমে তৈরি করা থাকে । spider হচ্ছে মূলত একটি কম্পোনেন্ট যেটা সাধারণত ওয়েব সাইটের কন্টেন্ট স্ক্র্যাপ করার জন্য ব্যাবহার করা হয় । এমনকি facebook, google এর ও নিজস্ব spider আছে
এরপর আছে runspider কমান্ড । কোন প্রজেক্টের জন্য এক বা একাধিক spider তৈরি করতে হয়, কিন্তু যদি সিম্পল কাজের জন্য customize কোন spider এর প্রয়োজন না হয় সেক্ষেত্রে মাঝে মাঝে এই কমান্ড দিয়েই কাজ চালানো যায়, এই কমান্ডটি মাঝে মাঝে দরকার হয় ।
এরপর আছে startproject, এটা দিয়ে কোন নতুন প্রজেক্ট তৈরি করার জন্য ব্যাবহার করা হয় ।
Create a new project
একটি নতুন প্রজেক্ট তৈরি করার জন্য নিচের কমান্ড টি দিতে হয় ।
scrapy startproject project_name
ধরা যাক আমরা এই প্রজেক্টের নাম দিলাম worldometers
একটি নতুন প্রজেক্ট তৈরি করার পর কিছু নতুন ফাইল তৈরি হয় ।
এরমধ্যে একটি হচ্ছে scrapy.cfg ফাইল । এই ফাইলের মধ্যে বিভিন্ন সেটিংস সেট করে দেওয়া যায় কিন্তু ডিফল্ট হিসেবে একটি ডিফল্ট সেটিংস থাকে । এছাড়াও ক্লাউডে ফাইল আপলোড করার অপশন ও এখানে দিয়ে দিতে হয় ।
এরভেতরে spider নামে ডিরেক্টরি থাকে এখানেই সকল spider ফাইল গুলো তৈরি করতে হয় ।
এরপর items.py ফাইলের মধ্যে ডাটা ক্লিনিং এর কাজগুলো করতে হয় ।
এরপর middlewares.py ফাইলের মধ্যে সকল request এবং response কোড গুলো লিখতে হয় ।
এরপর pipelines.py ফাইলের মধ্যে আমরা যে ডাটা গুলো স্ক্র্যাপ করবো সেগুলো ডাটাবেজে স্টোর করে রাখার কোড গুলো লিখতে হয় ।
এরপর settings.py ফাইল থাকে । এখানে প্রজেক্টের সেটিংস গুলো বলে দিতে হয় ।
worldometers project
আমরা এখন এই প্রজেক্টের জন্য worldometers সাইট থেকে প্রত্যেক দেশের নাম এবং জনগণ এর সংখ্যা নিবো । এরপর প্রত্যেক দেশের লিঙ্কে যেয়ে সেই দেশে কতো সালে কয়জন জনগণ ছিল এগুলাও নিবো ।
এখন যে ওয়েবসাইট টি স্ক্র্যাপ করতে চাই সেই লিঙ্ক টি কপি করে নিচের কমান্ড চালাতে হবে scrapy project এর ভেতরে যেয়ে ।
scrapy genspider countries https://www.worldometers.info/world-population/population-by-country/
এই কমান্ড চালানর আগে আমাদের শেষের / স্প্লাশ চিহ্ন কেটে দিবো এবং https:// এটা কেটে দিবো । কারণ scrapy অটোমেটিক ভাবেই শেষে একটি স্প্লাশ দিয়ে দেয় আবার এটা সব সময় http প্রটোকল ব্যাবহার করে । তাহলে এগুলো কেটে দিয়ে নিচের নিয়মে কমান্ডটি দিতে হবে ।
scrapy genspider countries www.worldometers.info/world-population/population-by-country
spiders ডিরেক্টরিতে এই spider টি তৈরি হবে ।
এখানে countries হচ্ছে এই স্পাইডার টির নাম । এটা যেকোনো প্রজেক্টে unique হতে হয় ।
এখন এই কমান্ড চালানোর পর spider ডিরেক্টরি তে গেলে দেখা যাবে যে countries.py নামে একটি স্পাইডার file তৈরি হয়েছে ।
এখানে name = countries দেওয়া আছে । একটি প্রজেক্টে একাধিক spider থাকতে পারে কিন্তু সবার নাম ইউনিক হবে ।
allowed_domains এ পুরো url না দিয়ে শুধু মাত্র domain name দিতে হবে । তাই বাকী অংশ টুকু কেটে দিতে হয় । এটা আমরা নিচের দেখিয়েছি ।
start_urls এ শুধু http দেওয়া আছে কারণ spider ডিফল্ট হিসেবে http দিয়ে দেয় । কিন্তু আমাদের এখানে https লাগে, সেজন্য আমাদের এডিট করে নিচের মতো করে https এডিট করে দিতে হয় ।
এখানে যে প্রপার্টি গুলো আছে সেগুলো ঠিক একি নামে হতে হবে কারণ এটা একটি টেম্পলেট । এখানে name, allowed_domains, start_urls, parse এই নামগুলো পরিবর্তন করে দিলে ঠিকমত কাজ করবে না।
Scrapy shell
scrapy shell ইন্সটল করার জন্য আমাদের এই নিচের কমান্ডটি চালাতে হবে
pip3 install ipython
এরপর টার্মিনালে scrapy shell
লিখে ইন্টার দিতে হবে তাহলেই ipython এর ইন্টারেক্টিভ সেল ওপেন হয়ে যাবে ।
এখানে scrapy shell ওপেন হওয়ার পর fetch
কমান্ডের ভেতর আমাদের টার্গেটেড সাইট টি দিয়ে দিতে হবে । কোন রেসপন্স যদি 404 আসে তাহলে বুঝে নিতে হবে যে সেটার পারমিশন নাই, আর 200 আসলে সেটার পারমিশন আছে ।
এরপরের কমান্ড fetch(r) দিয়ে বোঝায় সেই সাইট টা fetch করে নিয়ে আসছি । এরপর response.body দিয়ে বডিটা দেখিয়েছি টার্মিনালে।
এরপর view(response)
কমান্ড দিলে সেই স্ক্র্যাপ করা সাইট টি আমাদের ব্রাওজারে ওপেন হবে । আমাদের স্ক্র্যাপ করা সাইটটিতে javascript সহ দেখাবে কিন্তু scrapy কিন্তু জাভাস্ক্রিপ্ট চিনে না জাস্ট html, css স্ক্র্যাপ করে । সেজন্য অরিজিনাল ফরম্যাটটি দেখার জন্য ctrl + shift + i
দিয়ে ইন্সপেক্টর ওপেন করে ctrl + shift + p
দিয়ে সেখানে search bar এ javascript লিখে disable javascript সিলেক্ট করে রিফ্রেশ করলে original scrap করা সাইট টি দেখা যাবে ।
2. XPath expressions and CSS selector
xpath expression এর জন্য প্রথমে আমরা যে টেক্সটটি সম্পর্কে জানতে চাচ্ছি সেই ট্যাক্সটি সিলেক্ট করে ঐ টেক্সটের উপর রাইট ক্লিক করে inspect এ ক্লিক করতে হবে তাহলে সেই টেক্সটের html markup চলে আসবে । এরপর element ট্যাব এ ক্লিক করে ctrl+f চাপলে ফাইন্ডের অপশন বের হয়ে আসবে । এরপর এই h1 tag বের করার জন্য নিচের মতো করে xpath expression লিখতে হবে //h1
XPATH expression
এখন টার্মিনাল ওপেন করে নিচের কমান্ডটি দিতে হবে । সেটা একটা লিস্ট রিটার্ন করবে অর্থাৎ যে কয়টা h1 tag থাকবে সে কয়টা রিটার্ন করবে ।
>>> view(response)
# output : True>>> title_xpath = response.xpath(“//h1”)
# output : [ list of h1 tag. data will be shown in data property ]
যদি আমরা এই লিস্টের টেক্সট ডাটা গুলো দেখতে চাই তাহলে text() ফাংশনটি দিয়ে দিতে হবে ।
>>> title_xpath = response.xpath(“//h1/text()”)
এখন যদি আমরা শুধু টাইটেল ডাটা স্ট্রিং হিসেবে দেখতে চাই তাহলে শুধু get() মেথডটি কল করতে হবে ।
>>> title_xpath.get()
CSS selector
>>> title_css = response.css(“h1::text”)>>> title_css.get()
সাধারণত অধিকাংশ সময় xpath ব্যাবহার করা হয় কারণ এটাতে অনেক বেশী ফাংশনালিটি আছে ডাটা মেনুপুলেসনের জন্য কিন্তু splash এ css selector বেশী ব্যাবহার করা হয় । আর xpath এর query র চাইতে css selector এর query দেখতে অনেক ক্লিন ।
country_xpath
এখন আমরা দেশের নাম গুলো বের করতে চাই সেক্ষেত্রে inspection এ যেয়ে country র নাম সিলেক্ট করে দেখতে হবে এটা কোন স্কোপ এর মধ্যে আছে । এরপর xpath expression লিখতে হবে ।
>>> countries_xpath = response.xpath(“//td/a/text()”).getall()>>> countries_xpath
এই কমান্ড দিলে সকল দেশের নাম চলে আসবে কারণ দেশের নাম গুলো a tag এর মধ্যে আছে আর এই a tag গুলো td টেবিলের মধ্যে আছে । শুধু a tag নিলে পেজের মধ্যে অন্যান্য লিঙ্ক গুলোও কাউন্ট করে নিয়ে আসবে তাই আমরা শুধু teble এর মধ্যে যে a tag আছে সেগুলোই নিয়ে আসবো । আর এখানে শুধু get() এর পরিবর্তে getall() নিয়ে আসছি কারণ আমরা লিস্টের সকল টেক্সট ই নিয়ে আসতে চাই ।
country_css
>>> country_css = response.css(“td a::text”).getall()>>> country_css
spider project
এই প্রজেক্টে আমরা title এবং country বের করে নিয়ে আসবো সেজন্য spider এ আমরা title, country র xpath expression লিখে সেটাকে dictionary তে রিটার্ন করতে হয় সেজন্য সেটাকে yield এর মধ্যে দিয়েছি ।
এখন এই প্রজেক্ট রান করার জন্য terminal ওপেন করে `scrapy.cfg` এই কনফিগ ফাইলের ডিরেক্টরিতে যেয়ে নিচের মতো করে কমান্ড লিখে countries স্পাইডারটি রান করতে হবে ।
$ scrapy crawl countries
XPath expressions and CSS selector Query
xpath expression = XML Path Language
css selector = cascading style sheet
xpath এইচটিএমএল ওয়েবপেজের উপর থেকে নিচে পর্যন্ত দেখে যেতে পারে কিন্তু css সেটা পারে না । অপরদিকে xpath এর element selector কিছুটা কমপ্লেক্স কিন্তু css অনেকটা ক্লিন ।
যেমন আমরা যদি
<dev class=’menu dropdown’> …. </dev>
এই এলেমেন্ট সিলেক্ট করতে চাই সেজন্য xpath আর css selector এর এক্সপ্রেশন হবে নিম্নরূপ
<! — xpath →
//div[@class=’menu dropdown’]<! — css selector →
.menu.dropdown
xpath & css selector practice code
CSS selector Query
class, id
Class এর জন্য .
দিতে হয়
শুধু .intro দিলে উপড়ের html থেকে ২ টা এলিমেন্ট নিয়ে আসবে একটি হচ্ছে `<dev>` আরেকটি হচ্ছে `<span>` কিন্তু যদি আমরা শুধু `<dev>` এর intro ক্লাস নিয়ে আসতে চাই তাহলে `dev.intro` দিতে হবে ।
Id র জন্য #
দিতে হয়
ক্লাসের জন্য `#location` দিতে হবে । আর span এর যে ID আছে সেটা আনার জন্য `span#location` এভাবে লিখতে হবে ।
যদি `.bold` লিখি তাহলে bold ক্লাস আছে এরকম সকল এলিমেন্ট নিয়ে আসবে কিন্তু যদি `.bold.italic` লিখি তাহলে শুধুমাত্র এই দুটি ক্লাস একসাথে আছে সেগুলোই নিয়ে আসবে ।
foreign attribute
li[data-identifier=”7"] অথবা যদি শুধু data-identifier আনতে চাই তাহলে শুধু `data-identifier=”7"` লিখলেই হয়ে যাবে ।
value lookup (start with / end with / middle word)
a[href^=’https’] → যে লিঙ্ক গুলো https দিয়ে শুরু হবে
a[href$=’fr’] → যে লিঙ্কগুলোর শেষে fr থাকে
a[href~=’google’] / a[href*=’google’] → যে লিঙ্কগুলোর মাঝে যেকোনো জায়গায় google আছে ।
position
div.intro p → intro div এর আণ্ডারে যে প্যারাগ্রাফ গুলো আছে সব নিয়ে আসবে কিন্তু p এর আণ্ডারে কোন ইলিমেন্ট নিয়ে আসবে না ।
div.intro p, #location → p এর আণ্ডারে কোন id যদি location নামে পায় তাহলে সেটা নিয়ে আসবে এবং সাথে সকল peragraph ও নিয়ে আসবে ।
div.intro > p → সকল প্যারাগ্রাফ নিয়ে আসবে এবং সাথে p এর আণ্ডারে সকল direct children ও নিয়ে আসবে ।
CSS combinator
div.intro + p → intro ক্লাসযুক্ত div এর ঠিক immediate পর যদি p tag থাকে তাহলে সেটা নিয়ে আসবে কিন্তু যদি না থাকে তাহলে নিয়ে আসবে না যেমন div.intro + span দেই তাহলে সেটা নিবে না কারণ span ট্যাগ p ট্যাগ এর পর ।
div.intro ~ p → div এর পর যেকোনো জায়গায় p ট্যাগ থাকতে পারে ।
table ডাটা, nth child (position)
li:nth-child(1), li:nth-child(4) → টেবিলে 1 এবং ৪ নং পজিশনের ডাটা নিয়ে আসবে ।
li:nth-child(odd) → odd পজিশনের ডাটা নিয়ে আসবে ।
li:nth-child(even) → even পজিশনের ডাটা ।
Xpath expression
class
`//div[@class=’intro’ or @class=’outro’]/p/text()` → intro এবং outro ক্লাস এর সকল p teg এর টেক্সট নিয়ে আসতে হবে ।
a (link)
`//a/@href/text()` → সকল লিঙ্ক নিয়ে আসবে ।
`//a[starts-with(@href, ‘https’)]` → starts-with() মেথড ২ টা আর্গুমেন্ট নেয়, প্রথমটি হচ্ছে কোথায় খুঁজবে আর পরেরটি হচ্ছে কি খুঁজবে ।
`//a[ends-with(@href, ‘fr’)]` → শেষে fr থাকবে এইরকম লিঙ্ক নিয়ে আসবে ।
`//a[contains(text(), ‘France’)]` → text এ France লেখাটি থাকলেই নিয়ে আসবে ।
position
`//ul[@id=’items’]/li[1 or 4]` → 1 নাম্বার থেকে ৪ নাম্বার পজিশনের সকল আইটেম নিয়ে আসবে ।
`//ul[@id=’items’]/li[position()=1 or position()=4]` → শুধুমাত্র ১ নং এবং ৪ নং পজিশনের ডাটা নিয়ে আসবে ।
`//ul[@id=’items’]/li[position()=1 or position()=last()]` → প্রথম এবং শেষ পজিশনের ডাটা ।
`//ul[@id=’items’]/li[position() > 1]` → 1 নং পজিশন বাদে এর পরের সকল ডাটা নিয়ে আসবে ।
going up
`//p[@id=’unique’]/parent::node()` → unique আইডি যুক্ত প্যারাগ্রাফের ঠিক immediate প্যারেন্ট নোড নিয়ে আসে ।
`//p[@id=’unique’]/ancestor::node()` → প্যারেন্ট, তার প্যারেন্ট, তার প্যারেন্ট এরকম করে সব প্যারেন্ট নিয়ে আসে অর্থাৎ grand parent কিন্তু unique প্যারাগ্রাফ নিয়ে আসে না । এটা নিয়ে আসতে চাইলে নিচের কোয়েরি ব্যাবহার করতে হবে ।
`//p[@id=’unique’]/ancestor-or-self::node()` → সকল ancestor নিয়ে আসে ।
`//p[@id=’unique’]/preceding::h1` → শুধু h1 নিয়ে আসে ।
`//p[@id=’unique’]/preceding-sibling::node()` → পাশা পাশী ২ বা ততোধিক paragraph থাকলে সেগুলো নিয়ে আসে । অর্থাৎ presiding brothers
going down
`//div[@class=’intro’]/p` → intro ক্লাসযুক্ত div এর সকল paragraph নিয়ে আসবে ।
`//div[@class=’intro’]/child::node()` → উপড়েরটার মতো একি কাজ করে অর্থাৎ সকল child নিয়ে আসে ।
`//div[@class=’intro’]/following::node()` → এই div এর পরে যত ইলিমেন্ট আছে সবগুলো নিয়ে আসে ।
`//div[@class=’intro’]/following-sibling::node()` → একি প্যারেন্টের আণ্ডারে যতগুলো sibling আছে সবগুলো নিয়ে আসে অর্থাৎ intro div এর প্যারেন্ট body. body তে যতগুলো sibling আছে সবগুলো নিয়ে আসে ।
`//div[@class=’intro’]/descendant::node()` → intro div এর সকল children, grand children নিয়ে আসে ।
3. Project 1 : Spiders from A to Z
আমরা নিচের এই লিঙ্কের ডাটা গুলো আনতে চাচ্ছি ।
এই সাইট থেকে আমরা জাস্ট name আর country name এনেছিলাম এখন এই প্রত্যেকটা কান্ট্রির উপর হভার ওভার করলে লিঙ্ক দেখা যাবে এই লিঙ্ক টা আমাদের দরকার ।
এখন countries.py ফাইলে যেয়ে নিচের কোড টুকু দিয়ে রান করি ।
countries = response.xpath("//td/a").getall()
এরপর এটা রান করি ।
scrapy crawl countries
এটা রান করলে সকল country র লিঙ্ক এসে যাবে ।
এখন নিচের এই কমান্ড দিয়ে scrapy shell এ ঢুকি সাথে যে সাইট টি নিয়ে কাজ করবো সেটাতেও ।
$ scrapy shell "http://www.worldometers.info/world-population/population-by-country/"
এখন shell এ নিচের কমান্ড গুলো দেই ।
> countries = response.xpath("//td/a")> countries
তাহলে কান্ট্রি গুলো প্রিন্ট করবে ।
response অবজেক্টের বদলে selector অবজেক্টের আন্ডারে যদি আমরা xpath expression implement করি তাহলে সব সময় .//
দিয়ে শুরু করতে হয় । এখন
এখন প্রত্যেক অবজেক্টের ভেতর name আর link এসে পরবে ।
এখন প্রত্যেক লিঙ্কে রিকোয়েস্ট করার জন্য আমরা request লাইব্রেরি ব্যাবহার করবো কারণ scrapy তে fetch মেথড ব্যাবহার করা যায় না ।
এটা আমরা ৩ ভাবে করতে পারি ।
absolute_url = f"https://www.worldometers.info{link}"...................yield scrapy.Request(url=absolute_url)
এভাবে একভাবে করা যায় । এই লাইনগুলো দেওয়ার পর নিচের কমান্ড দিয়ে রান করবো ।
scrapy crawl countries
এখন এই কমান্ড দিলে প্রজেক্ট রান করবে এবং রিকোয়েস্ট করে ডাটা নিয়ে আসবে ।
absolute_url = response.urljoin(link)
এটা হচ্ছে দ্বিতীয় নিয়ম , এটা দিয়েও কাজ করা যায় ।
উপরের এই লাইন গুলো বাদ দিয়ে শুধু নিচের এই লাইন দিয়েও একি কাজ করা যায় ।
yield response.follow(url=link)
এখন প্রত্যেকটি দেশের লিঙ্কে যেয়ে সেই দেশের name, year এবং population আনবো । কত সালে কত জনগণ ছিল ঐগুলো আনবো ।
(//table[@class='table table-striped table-bordered table-hover table-condensed table-list'])[1]/tbody/tr
এখানে xpath expression এর মানে হচ্ছে যে একাধিক টেবিল আছে সেজন্য table এর মধ্যে @class এর ভেতরে ঐ টেবিলের ক্লাস নেইম গুলো লিখেছি । এরপর first bracket এর পর [1] এর মানে হচ্ছে একি ক্লাস নেইমের আন্ডারে একাধিক টেবিল আছে সেখান থেকে দ্বিতীয় টেবিলটা নিয়েছি এরপর ঐ টেবিলের tbody/tr এই রো নিয়েছি এখানে ১৮ টার মতো রো আছে । এখান থেকে শুধুমাত্র year আর population এক্সট্রাক্ট করে নিয়েছি ।
response.follow() এর ভেতর callback দিয়েছি আর সাথে একটি meta ডাটা ও দিয়েছি । অর্থাৎ এই মেথডের একটি প্রপার্টি name টা পাস করে দিয়েছি এটা আবার parse_country এর ভেতর নিচের এই কোড দিয়ে এক্সেস করছি ।
name = response.request.meta['country_name']
Building dataset:
এখন এই ডাটাকে আমরা এক্সপোর্ট করবো । এটাকে json, csv or xml ফাইল ফরম্যাটে এক্সপোর্ট করতে পারবো ।
scrapy crawl countries -o population_dataset.json
এই কমান্ড দিলে প্রজেক্ট ডিরেক্টরিতে population_dataset.json নামে একটি ফাইল তৈরি হয়ে সেখানে জেসন ফরম্যাটে ডাটা সেভ হবে ।
scrapy crawl countries -o population_dataset.csv
উপরের এই কমান্ড দিয়ে দাতাটাকে csv ফরম্যাটে সেভ করবো ।
scrapy crawl countries -o population_dataset.xml
এই কমান্ড দিয়ে ডাটাকে xml ফরম্যাটে সেভ করবো ।
4. Project 2 : Dealing with Multiple pages
এখন আমরা নিচের এই সাইট টি স্ক্র্যাপ করবো ।
এজন্য এই সাইটের রুট ডিরেক্টরিতে যেয়ে /robot.txt
তে ইন্টার দিয়ে চেক করে নিবো যে এই সাইট টি স্ক্র্যাপ করা যাবে কিনা ।
এরপর ctrl+shift+i
প্রেস করে ইন্সপেক্ট
ওপেন করে এরপর ctrl+shift+p
প্রেস
সেখানে কমান্ড প্রম্পট এ javascript লিখে ড্রপ ডাউন থেকে এটাকে disable করে দিবো । এরপর পেজ রিফ্রেশ করবো ।
এখন প্রজেক্ট ডিরেক্টরি তে যেয়ে নিচের কমান্ড দিয়ে প্রজেক্ট তৈরি করবো ।
$ scrapy startproject cigabuy
এরপর একটি স্পাইডার তৈরি করার জন্য প্রজেক্টের ভেতর যেয়ে নিচের কমান্ড টি দিবো ।
$ cd cigabuy
$ scrapy genspider special_offers www.cigabuy.com/specials.html
এখন spider এ যেয়ে special_offer ফাইলে নিচের কোড টুকু এডিট করে দিতে হবে ।
allowed_domains = ['www.cigabuy.com/specials.html']start_urls = ['http://www.cigabuy.com/specials.html']
এখানে allowed_domains এর শেষের /specials.html এই অংশ টুকু কেটে দিবো আর start_urls এর প্রথমে http এর জায়গায় https দিয়ে দিবো আর শেষের / এটাও কেটে দিবো ।
এরপর নিচের কোড গুলো লিখবো ।
এখানের xpath গুলো কিভাবে জেনারেট করেছি সেটা নিচের এই স্কিনশটে দেখানে হোলও ।
এখন নিচের এই কমান্ড টি চালিয়ে স্ক্রেপি execute করি ।
$ scrapy crawl special_offers -o dataset.json
কোথায় কোনও utf প্রব্লেম থাকলে settings.py ফাইলে নিচের লাইনটি অ্যাড করে দিয়ে রান করলে এই প্রব্লেম আর হবে না ।
FEED_EXPORT_ENCODING = 'utf-8'
Spoofing(প্রতারণা করা) request headers:
scrapy দিয়ে রিকোয়েস্ট করার সময় user-agent এ scrapy এবং এর ভার্সন নাম্বার ডিফল্ট হিশেবে সেট হয়ে যায়, এজন্য অনেক সময় আমাদের রিকোয়েস্ট কে ব্লক করে দিতে পারে , সেজন্য user-agent কে ওভার রাইড করতে হয় ।
$ scrapy shell "https://www.cigabuy.com/specials.html
এই কমান্ড দিলে interactive shell এ প্রবেশ করে ।
এখান থেকে আমরা এই কমান্ড গুলো ব্যাবহার করতে পারি ।
scrapy, crawler, request, response, settings, spider ইত্যাদি ।
pip3 install ipython
এই কমান্ড দিয়ে ipython ইন্সটল করে এরপর scrapy shell
কমান্ড দিয়ে interactive shell এ প্রবেশ করি , এরপর নিচের কমান্ড গুলো দেই ।
>>> req=scrapy.Request(url='https://www.cigabuy.com/specials.html')>>> fetch(req)>>> response.request.headers
প্রথমে রিকোয়েস্ট রেডি করে fetch() দিয়ে রিকোয়েস্ট ডাটা নিয়ে এসে header দেখলাম ।
এখান থেকে user-agent টাকে পরিবর্তন করতে হবে ।
এটা বিভিন্ন ভাবে dynamiclly পরিবর্তন করা যায় , প্রসেস গুলো আমরা নিচে দেখাচ্ছি । প্রথমে settings.py ফাইলে যেতে হবে এরপর browser open করে developer tool open করে network tab এ যেয়ে ctrl+r
দিয়ে পেজ রিফ্রেশ করে special.html
এ click করে header সেকশনে গেলে দেখা যাবে user-agent এখান থেকে এই লেখাটি কপি করি ।
এরপর সেটাকে settings.py ফাইলে USER_AGENT এ দিয়ে দেই ।
USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
এটা শুধুমাত্র একটা রিকোয়েস্টের সাথে যাবে কিন্তু যদি আরও অনেক রিকোয়েস্ট করতে হয় concurrently তখন ২ ভাবে করা যায় একভাবে হচ্ছে এই setting.py ফাইলে নিচের লাইন গুলো লিখবো ।
DEFAULT_REQUEST_HEADERS = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'}
settings ফাইলে পরিবর্তনের পর নিচের লাইনগুলো special_offers.py ফাইলে লিখি।
এখানে মূলত start_urls লাইনটি কমেন্ট করে দিয়েছি ।
এরপর start_request() নামে নতুন একটি মেথড তৈরি করেছি
এরপর if কন্ডিশনের ভেতর yield এর ভেতর User-Agent দিয়ে দিয়েছি ।
শেষে for loop এর ভেতর User-Agent দিয়ে দিয়েছি।
এটা এখন একসাথে একাধিক রিকোয়েস্টের জন্য dynamically কাজ করবে ।
এখন নিচের এই কমান্ড দিলে প্রজেক্ট রান হবে ।
scrapy crawl special_offers
দ্বিতীয় পর্ব নিচের এই লিঙ্কে