Lấy danh sách dự án mà người dùng đã đóng góp trên GitLab

Trong quá trình xây dựng hệ thống thống kê số lượng commit theo từng thành viên, một bước quan trọng là xác định các dự án mà người dùng đã tham gia. Trên giao diện người dùng của GitLab, thông tin này có thể xem được qua trang "Contributed projects". Tuy nhiên, API chính thức của GitLab không cung cấp endpoint nào để truy xuất trực tiếp dữ liệu này. Do đó, giải pháp khả thi hiện tại là mô phỏng hành vi người dùng bằng cách đăng nhập và phân tích nội dung HTML từ trang web.

Lấy token CSRF từ trang đăng nhập

GitLab sử dụng token CSRF để bảo vệ form đăng nhập. Trước khi gửi yêu cầu đăng nhập, cần trích xuất token này từ trang /users/sign_in. Có thể dùng thư viện như lxml để phân tích DOM và lấy giá trị token:

import requests
from lxml import etree

base_url = 'http://your-gitlab-instance'
signin_url = f'{base_url}/users/sign_in'

session = requests.Session()
response = session.get(signin_url)
doc = etree.HTML(response.text)
csrf_token = doc.xpath('//input[@name="authenticity_token"]/@value')[0]

Thực hiện đăng nhập

Sau khi có token, tiến hành gửi yêu cầu POST đến endpoint đăng nhập. Ví dụ dưới đây giả định hệ thống dùng LDAP; nếu dùng cơ chế đăng nhập mặc định, chỉ cần thay đổi URL tương ứng:

login_url = f'{base_url}/users/auth/ldapmain/callback'
payload = {
    'utf8': '✓',
    'authenticity_token': csrf_token,
    'username': 'your_username',
    'password': 'your_password'
}
session.post(login_url, data=payload)

Truy xuất danh sách dự án đã đóng góp

GitLab cung cấp phiên bản JSON của trang "contributed projects" qua URL có đuôi .json. Nội dung HTML trong phản hồi JSON có thể được phân tích để trích xuất tên dự án:

contrib_url = f'{base_url}/users/target_user/contributed.json'
resp = session.get(contrib_url)
html_content = resp.json()['html']
doc = etree.HTML(html_content)

project_nodes = doc.xpath('//span[@class="project-full-name"]')
project_list = [
    node.xpath('string(.)').strip().replace('\n', '').replace(' ', '')
    for node in project_nodes
]

Mã hoàn chỉnh

import requests
from lxml import etree

GITLAB_URL = 'http://your-gitlab-instance'
USERNAME = 'your_login_username'
PASSWORD = 'your_login_password'

def create_authenticated_session():
    session = requests.Session()
    signin_resp = session.get(f'{GITLAB_URL}/users/sign_in')
    html = etree.HTML(signin_resp.text)
    token = html.xpath('//input[@name="authenticity_token"]/@value')[0]

    login_data = {
        'utf8': '✓',
        'authenticity_token': token,
        'username': USERNAME,
        'password': PASSWORD
    }
    session.post(f'{GITLAB_URL}/users/auth/ldapmain/callback', data=login_data)
    return session

def fetch_contributed_projects(target_user):
    sess = create_authenticated_session()
    json_url = f'{GITLAB_URL}/users/{target_user}/contributed.json'
    response = sess.get(json_url)
    content_html = response.json()['html']
    doc = etree.HTML(content_html)

    spans = doc.xpath('//span[@class="project-full-name"]')
    projects = [s.xpath('string(.)').strip().replace('\n', '').replace(' ', '') for s in spans]
    return projects

if __name__ == '__main__':
    projects = fetch_contributed_projects('some_gitlab_user')
    print(projects)

Thẻ: gitlab python web scraping lxml requests

Đăng vào ngày 9 tháng 6 lúc 02:22