- vừa được xem lúc

Multithreading Selenium, Docker và Django (docker-compose)

0 0 50

Người đăng: Kính Gia Hà

Theo Viblo Asia

Giới thiệu

Phần trước mình có giới thiệu qua cách làm việc với django, selenium và docker. Tuy nhiên do nhu cầu công việc nên chúng ta cần chạy song song giữa selenium và django, cùng với đó ta có thể chạy song song nhiều tab driver. Tuy nhiên cách này mình chỉ chạy được trên firefox. Còn chorme nó chỉ chạy một driver. Ở đây mình sẽ sử dụng Selenium Hub và Docker Hub để chạy nhiều node firefox. Đồng thời mình sử dụng Thread của Python để chạy song song tác vụ selenium và django, nhằm ngăn chặn quá trình trang web bị delay khi chạy selenium. Chúng ta sử dụng ajax để thực hiện hành động từ phía server. Ở đây chúng ta cũng có thể sử dụng channels. Nhưng trong bài viết này mình sẽ không sử dụng channels để thực hiện việc đó

image.png image.png

Cài đặt

Cài đặt project

pip install django
django-admin startproject app
django-admin startapp product

Khởi tạo project

Django

Sau khi khởi tạo project xong.

app app __init__.py asgi.py setting.py urls.py wsgi.py product __init__.py admin.py apps.py models.py test.py views.py
manage.py

Chỉnh sửa models.py trong app product Trong file này bạn tạo một model Product.

from django.db import models
from django.contrib.auth.models import User class Product(models.Model): name = models.CharField(max_length=200) def __str__(self) -> str: return self.name

Tạo 1 file urls.pygetData.py, thư mục templates và trong templates có product.html trong app product

app app __init__.py asgi.py setting.py urls.py wsgi.py product __init__.py admin.py apps.py getData.py models.py urls.py test.py views.py templates product.html
manage.py

Chỉnh sửa urls.py vừa khởi tạo.

from django.conf import settings
from . import views app_name = 'product' urlpatterns = [ path('', views.home, name ='products'), ath('crawl/', views.getData),
]

Chinh file views.py trong app product. Ở đây chúng ta sử dụng thread để thực hiện lấy dữ liệu.

from django.shortcuts import render
from django.http import JsonResponse
from .models import *
from .getData import *
from django.shortcuts import render
import threading def home(request): products = Product.objects.all() return render(request, 'product.html', {"products": products}) def getDataAjax(request): if request.is_ajax(): data_scrap() def getData(request): thread = threading.Thread(target=getDataAjax,args=[request]) thread.daemon = True thread.start() thread.join() return JsonResponse({})

Chỉnh sửa urls.py trong app

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns urlpatterns = [ path('admin/', admin.site.urls), path('', include('product.urls')),
]

Selenium

Chỉnh sửa file getData.py trong app Product. Tại đây chúng ta sử dụng selenium để thực hiện lấy dữ liệu. Và thread để lưu dữ liệu đã lấy vào database.

import time
from selenium import webdriver
from .models import *
# Import packages
from selenium import webdriver from bs4 import SoupStrainer
from bs4 import BeautifulSoup
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from .models import Product
import threading def data_scrap(): driver = webdriver.Remote("http://selenium-hub:4444/wd/hub", DesiredCapabilities.FIREFOX) driver.get("https://github.com/giakinh0823?tab=repositories") time.sleep(2) htmlSource = driver.page_source only_class = SoupStrainer("div", {"id": "user-repositories-list"}) list_product = BeautifulSoup(htmlSource, "html.parser", parse_only=only_class) for item in list_product.findAll("h3", {"class": "wb-break-all"}): name = str(item.find("a", attrs={"itemprop": "name codeRepository"}).text) print(name) thread = threading.Thread(target=save_product, args=[name]) thread.daemon=True thread.start() time.sleep(3) driver.quit() def save_product(name): product = Product.objects.create(name =name) product.save()

Templates

Chỉnh sửa file product.html trong templates

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head> <body> <h1>Crawl data</h1> <button id="getdata" onClick="getData()">Get data</button> <ul> {% for product in products %} <li>{{product.name}}</li> {% endfor %} </ul> <script> const getDataAjax = () => { $.ajax({ type: "GET", url: 'crawl/', data: '', dataType: 'json', success: function (data) { console.log(data) } }); } </script> </body> </html>

Docker

Đầu tiên bạn hãy tạo một file Dockerfile và docker-compose.yml trong project app

app app __init__.py asgi.py setting.py urls.py wsgi.py product __init__.py admin.py apps.py getData.py models.py urls.py test.py views.py templates product.html
docker-compose.yml
Dockerfile
manage.py

Chỉnh sửa file Dockerfile. Ở đây mình ta ra một thư mục product và coppy requirements.txt vào thư mục đó. Sau đó install requirements.txt và coppy tất cả project của mình vào thư mục product

FROM python:3
ENV PYTHONUNBUFFERED=1
WORKDIR /product
COPY requirements.txt /product/
RUN apt-get update \ && apt-get -y install libpq-dev gcc
RUN pip install -r requirements.txt
COPY . . EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Chỉnh sửa file docker-compose.yml. Ở đây ta có 1 database db có image postgres và database này có tên product và username = admin, password = admin. Chúng ta có selenium-hub với GRID_MAX_SESSION=50, trong selenium-hu ta có node-chorme và node-firefox. Với node-firefox ta có NODE_MAX_SESSION = 20. Hai node-chorme và node-firefox có depends_on là selenium-hub. Ta cũng có web có depends_on là db

version: "3.9" services: db: image: postgres volumes: - ./data/db:/var/lib/postgresql/data environment: - POSTGRES_DB=product - POSTGRES_USER=admin - POSTGRES_PASSWORD=admin web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/product ports: - "8000:8000" depends_on: - db selenium-hub: image: selenium/hub ports: - "4444:4444" environment: GRID_MAX_SESSION: 50 GRID_BROWSER_TIMEOUT: 300 GRID_TIMEOUT: 300 chrome: image: selenium/node-chrome depends_on: - selenium-hub environment: HUB_PORT_4444_TCP_ADDR: selenium-hub HUB_PORT_4444_TCP_PORT: 4444 NODE_MAX_SESSION: 1 NODE_MAX_INSTANCES: 1 firefox: image: selenium/node-firefox depends_on: - selenium-hub environment: HUB_PORT_4444_TCP_ADDR: selenium-hub HUB_PORT_4444_TCP_PORT: 4444 NODE_MAX_SESSION: 20 NODE_MAX_INSTANCES: 20

Tạo và chỉnh sửa file requirements.txt trong project app

app app __init__.py asgi.py setting.py urls.py wsgi.py product __init__.py admin.py apps.py getData.py models.py urls.py test.py views.py templates product.html
docker-compose.yml
Dockerfile
requirements.txt
manage.py

requirements.txt

asgiref==3.4.1
beautifulsoup4==4.9.3
bs4==0.0.1
certifi==2021.5.30
charset-normalizer==2.0.4
colorama==0.4.4
configparser==5.0.2
crayons==0.4.0
Django==3.2.6
ftfy==6.0.3
idna==3.2
numpy==1.21.1
pandas==1.3.1
Pillow==8.3.1
python-dateutil==2.8.2
pytz==2021.1
requests==2.26.0
selenium==3.141.0
six==1.16.0
soupsieve==2.2.1
sqlparse==0.4.1
urllib3==1.26.6
wcwidth==0.2.5
webdriver-manager==3.4.2
Django>=3.0,<4.0
psycopg2-binary>=2.8
psycopg2==2.9.1

Build và Run project

docker-compose build
docker-compose run web python manage.py makemigrations
docker-compose run web python manage.py migrate
docker-compose up

Sau đó bạn vào http://127.0.0.1:8000/ để xem kết quả

Cảm ơn các bạn đã quan tâm

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 396

- vừa được xem lúc

Phần 1: Giới thiệu về Kubernetes

Kubernetes là gì. Trang chủ: https://kubernetes.io/. Ai cần Kubernetes.

0 0 100

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 1- Lịch sử)

1. Vì sao nên sử dụng. . .

0 0 104

- vừa được xem lúc

Docker - những kiến thức cơ bản phần 1

Giới thiệu. Nếu bạn đang làm ở một công ty công nghệ thông tin, chắc rằng bạn đã được nghe nói về Docker.

0 0 78

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 2 - Dockerfile)

1. Mở đầu.

0 0 67

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 3: Docker-compose)

1. Mở đầu. . .

0 0 121