# Web Scraping

## **Web Scraping là gì?**

**Web Scraping là gì và tại sao chúng ta cần biết?**\
Web scraping là quá trình phân tích nội dung HTML của một trang web và trích xuất dữ liệu từ đó. Quá trình này thường được thực hiện bằng phần mềm tự động hoặc các script, thực hiện những gì trình duyệt web làm: mở trang web, tìm kiếm thông tin cụ thể, và thu thập hoặc lưu trữ thông tin đó.

Web scraping rất hữu ích và được sử dụng rộng rãi trong nhiều tình huống. Dưới đây là một số ví dụ ngoài bảo mật mà nó có thể hỗ trợ:

* **Khoa học dữ liệu và Học máy:** Hầu hết các mô hình học máy cần dữ liệu, và web scraping có thể được sử dụng để thu thập dữ liệu đó, như thu thập bình luận trên mạng xã hội để phân tích cảm xúc.
* **Nghiên cứu thị trường:** Các công ty và nhà nghiên cứu có thể sử dụng web scraping để thu thập thông tin về sản phẩm, giá cả, tính năng và đánh giá của khách hàng, phục vụ phân tích xu hướng hoặc đánh giá đối thủ cạnh tranh.
* **Thu thập nội dung web:** Một người hoặc công ty có thể sử dụng web scraping để thu thập thông tin về một chủ đề, như thu thập công thức nấu ăn và đưa chúng vào một cơ sở dữ liệu.
* **Tích hợp dữ liệu:** Web scraping cũng có thể thu thập dữ liệu từ nhiều trang và kết hợp chúng vào một nơi duy nhất, như trang so sánh giá.

Trước khi tiếp tục, cần lưu ý rằng web scraping có thể dẫn đến các trách nhiệm pháp lý, như vi phạm điều khoản sử dụng của trang web hoặc luật bảo vệ dữ liệu cá nhân. Vì vậy, khi bắt đầu một dự án web scraping, cần xem xét các khía cạnh này.

PowerShell cung cấp các công cụ rất mạnh mẽ và hữu ích cho Web Scraping nhờ vào sức mạnh của .NET đằng sau nó. Web Scraping thường bao gồm các bước: tạo yêu cầu, phân tích phản hồi nhận được, trích xuất dữ liệu cần thiết, chuẩn hóa và lưu trữ dữ liệu đã trích xuất. PowerShell cung cấp các công cụ giúp công việc của chúng ta dễ dàng hơn trong từng bước này. Hãy cùng xem xét:

## HTTP Requests

PowerShell hỗ trợ HTTP requests với các cmdlet **Invoke-WebRequest** và **Invoke-RestMethod**. Những cmdlet này cho phép gửi yêu cầu GET hoặc POST đến một trang web và xử lý phản hồi từ máy chủ.

## Invoke-WebRequest

Sử dụng cmdlet **Invoke-WebRequest**, bạn có thể tạo một yêu cầu HTTP và nhận phản hồi từ máy chủ web. Đây là một công cụ rất mạnh mẽ, cho phép chúng ta tùy chỉnh công việc của mình với nhiều tham số quen thuộc từ các cmdlet đã xem xét trước đó.

<figure><img src="/files/39GwBlBtuFPVhozztAuJ" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QNBmUPdD4gt8D1U8CPPU" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/UIOLsgbURoX4aDWWHvas" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/co140mlwLPNFzyt6uPzt" alt=""><figcaption></figcaption></figure>

Dưới đây là cách thực hiện yêu cầu web đơn giản nhất:

```powershell
Invoke-WebRequest -Uri "https://viettaliii.gitbook.io"
```

<figure><img src="/files/q7DzkGwDb3WEkFti9Gxg" alt=""><figcaption></figcaption></figure>

Yêu cầu này sử dụng phương thức GET vì phương thức mặc định là GET và chúng ta không chỉ định khác đi. Dưới đây, chúng ta thực hiện yêu cầu với phương thức POST, thay vì GET:

{% code overflow="wrap" %}

```powershell
Invoke-WebRequest -Uri "https://letsdefend.io" -Method 'POST'
```

{% endcode %}

Tiếp theo, thêm tên đăng nhập và mật khẩu vào yêu cầu:

{% code overflow="wrap" %}

```powershell
$body = @{
    'username' = 'admin'
    'password' = 'p@ssw0rd'
}
Invoke-WebRequest -Uri "https://letsdefend.io" -Method 'POST' -Body $body
```

{% endcode %}

Cuối cùng, thêm token vào header của yêu cầu:

{% code overflow="wrap" %}

```powershell
$token = "LetsDefendisGreat/andThisIsToken"
$headers = @{
    'Authorization' = 'Bearer ' + $token
}
$body = @{
    'username' = 'admin'
    'password' = 'p@ssw0rd'
}
Invoke-WebRequest -Uri "https://letsdefend.io" -Headers $headers -Method 'POST' -Body $body
```

{% endcode %}

Chúng ta đã thực hiện yêu cầu với **Invoke-WebRequest**. Bây giờ, chỉ cần xử lý phản hồi nhận được.

## HTML Parsing

Cmdlet **Invoke-WebRequest** chứa nội dung HTML của trang web, có thể truy cập thông qua thuộc tính `.Content` hoặc `.ParsedHtml`. Các thuộc tính này cho phép phân tích nội dung HTML và truy cập các thẻ, lớp, và ID HTML cụ thể.

Cách đơn giản nhất là gán yêu cầu vào một biến và gọi thuộc tính `.Content` của biến đó như sau:

{% code overflow="wrap" %}

```powershell
$token = "LetsDefendisGreat/andThisIsToken"
$headers = @{
    'Authorization' = 'Bearer ' + $token
}
$body = @{
    'username' = 'admin'
    'password' = 'p@ssw0rd'
}
$response = Invoke-WebRequest -Uri "https://letsdefend.io" -Headers $headers -Method 'POST' -Body $body
$response.Content
```

{% endcode %}

Khi chạy script này, phản hồi từ máy chủ web tại letsdefend.io sẽ được hiển thị trên màn hình dưới dạng HTML.

<figure><img src="/files/yAOOa2JlIyE2tmLhnuxC" alt=""><figcaption></figcaption></figure>

Cách đơn giản nhất để lưu kết quả này vào một tệp là sử dụng cmdlet **Out-File**. Khi thay đổi dòng cuối của mã thành như sau, kết quả sẽ được lưu vào tệp **LetsDefendResponse.html** trong thư mục mà script của chúng ta chạy:

{% code overflow="wrap" %}

```powershell
$token ="LetsDefendisGreat/andThisIsToken"
$headers = @{
    'Authorization' = 'Bearer ' + $token
}
$body = @{
    'username' = 'admin'
    'password' = 'p@ssw0rd'
}
$response = Invoke-WebRequest -Uri "https://letsdefend.io" -Headers $headers -Method 'POST' -Body $body
$response.Content | Out-File -FilePath "LetsDefendResponse.html"
```

{% endcode %}

Cmdlet **Invoke-WebRequest** của PowerShell lưu trữ phản hồi trong một đối tượng **BasicHtmlWebResponseObject**. Chúng ta đã truy cập thuộc tính **.Content** của đối tượng này ở trên, nhưng đối tượng này còn có các thuộc tính khác, như trong bảng dưới đây.

<figure><img src="/files/S6bWDJdXKlRqJTwmeu8f" alt=""><figcaption></figcaption></figure>

Dưới đây là cách sử dụng các thuộc tính của **BasicHtmlWebResponseObject** trong PowerShell. Trước tiên, hãy sắp xếp lại script như sau:

{% code overflow="wrap" %}

```powershell
$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'

Write-Host "BaseResponse : " $response.BaseResponse
Write-Host "Encoding : " $response.Encoding
Write-Host "RawContentLength : " $response.RawContentLength
Write-Host "RelationLink : " $response.RelationLink
Write-Host "StatusCode : " $response.StatusCode
Write-Host "StatusDescription : " $response.StatusDescription
Write-Host "Images : " $response.Images
Write-Host "InputFields : " $response.InputFields
Write-Host "Links : " $response.Links
Write-Host "Reply Headers"
Write-Host "==================================="
$response.Headers
```

{% endcode %}

Khi chạy script này, chúng ta sẽ thấy các kết quả bao gồm:

* **BaseResponse**: Phản hồi cơ bản từ máy chủ.
* **Encoding**: Kiểu mã hóa của phản hồi.
* **RawContentLength**: Độ dài của nội dung thô.
* **RelationLink**: Liên kết quan hệ (nếu có).
* **StatusCode**: Mã trạng thái của phản hồi (ví dụ: 200 cho thành công).
* **StatusDescription**: Mô tả trạng thái của phản hồi.
* **Images**: Tất cả các hình ảnh có trong trang.
* **InputFields**: Các trường nhập liệu trên trang.
* **Links**: Các liên kết trong trang.
* **Headers**: Tất cả các header trong phản hồi

<figure><img src="/files/aXEoWn5vhvhBiXYXBmSH" alt=""><figcaption></figcaption></figure>

Đối tượng **BasicHtmlWebResponseObject** trong PowerShell không chỉ lưu nội dung của phản hồi mà còn chứa thông tin tiêu đề của giao thức HTTP. Điều này cho phép chúng ta kiểm tra tính hợp lệ của trang mà không cần xử lý nội dung, ví dụ bằng cách sử dụng thuộc tính **StatusCode** để biết mã trạng thái (200 cho thành công, 404 cho không tìm thấy).

Một tính năng hữu ích khác là PowerShell tự động phân tích các nội dung quan trọng mà ta cần, chẳng hạn như **Links** và **Images**, và lưu chúng vào các trường tương ứng **Images**, **Links**, và **InputFields**. Nếu không có tính năng này, ta sẽ phải lấy nội dung từ **Content** rồi tự xử lý và tìm kiếm các phần tử HTML cần thiết như `<a>`, `<img>`, `<input>` trong mã của mình.

Tuy nhiên, đầu ra của các trường này vẫn có thể phức tạp. Ví dụ, khi nhìn vào **Links**, bạn sẽ thấy một khối lớn mã HTML.

```html
Links: @{innerHTML=Search; innerText=Search; outerHTML=Search; outerText=Search; tagName=A; id=gb_1; class=gbzt gbz0l gbp1; href=https://www.google.com.tr/webhp?tab=ww} @{innerHTML=Images; innerText=Images; outerHTML= Images; outerText=Images; tagName=A; id=gb_2; class=gbzt; href=https://www.google.com/imghp?hl=tr&tab=wi} @{innerHTML=Maps; innerText=Maps; outerHTML=Maps; outerText=Maps; tagName=A; id=gb_8; class=gbzt; href=https://maps.google.com.tr/maps?hl=tr&tab=wl} @{innerHTML=Play; innerText=Play; outerHTML=Play ; outerText=Play; tagName=A; id=gb_78; class=gbzt; href=https://play.google.com/?hl=tr&tab=w8} @{innerHTML=YouTube; innerText=YouTube; outerHTML=YouTube ; outerText=YouTube; tagName=A; id=gb_36; class=gbzt; href=https://www.youtube.com/?tab=w1} @{innerHTML=News; innerText=News; outerHTML=News ; outerText=News; tagName=A; id=gb_426; class=gbzt; href=https://news.google.com/?tab=wn} @{innerHTML=Gmail; innerText=Gmail; outerHTML=Gmail; outerText=Gmail; tagName=A; id=gb_23; class=gbzt; href=https://mail.google.com/mail/?tab=wm} @{innerHTML=Drive; innerText=Drive; outerHTML=Drive ; outerText=Drive; tagName=A; id=gb_49; class=gbzt; href=https://drive.google.com/?tab=wo} @{innerHTML=More more; innerText=More; outerHTML=More ; outerText=More; tagName=A; aria-haspopup=true; id=gbztm; class=gbgt; aria-owns=gbd; href=https://www.google.com.tr/intl/tr/about/products?tab=wh} @{innerHTML=Calendar; innerText=Calendar; outerHTML=Calendar; outerText=Calendar; tagName=A; id=gb_24; class=gbmt; href=https://calendar.google.com/calendar?tab=wc} @{innerHTML=Translation; innerText=Translation; outerHTML=Translation; outerText=Translation; tagName=A; id=gb_51; class=gbmt; href=https://translate.google.com.tr/?hl=tr&tab=wT} @{innerHTML=Books; innerText=Books; outerHTML=Books; outerText=Books; tagName=A; id=gb_10; class=gbmt; href=https://books.google.com.tr/?hl=tr&tab=wp} @{innerHTML=Shopping; innerText=Shopping; outerHTML=Shopping; outerText=Shopping; tagName=A; id=gb_6; class=gbmt; href=https://www.google.com.tr/shopping?hl=tr&source=og&tab=wf} @{innerHTML=Blogger; innerText=Blogger; outerHTML=Blogger; outerText=Blogger; tagName=A; id=gb_30; class=gbmt; href=https://www.blogger.com/?tab=wj} @{innerHTML=Finance; innerText=Finance; outerHTML=Finance; outerText=Finance; tagName=A; id=gb_27; class=gbmt; href=https://www.google.com/finance?tab=we} @{innerHTML=Photos; innerText=Photos; outerHTML=Photos; outerText=Photos; tagName=A; id=gb_31; class=gbmt; href=https://photos.google.com/?tab=wq&pageId=none} @{innerHTML=Documents; innerText=Documents; outerHTML=Documents; outerText=Documents; tagName=A; id=gb_25; class=gbmt; href=https://docs.google.com/document/?usp=docs_alc} @{innerHTML=Even more »; innerText=Even more »; outerHTML=Even more »; outerText=Even more »; tagName=A; class=gbmt; href=https://www.google.com.tr/intl/tr/about/products?tab=wh} @{innerHTML=< SPAN id=gbi4s1>Sign in; innerText=Sign in; outerHTML= Sign in; outerText=Sign in; tagName=A; onclick=gbar.logger.il(9,{l:'i'}); id=gb_70; class=gbgt; href=https://accounts.google.com/ServiceLogin?hl=tr&passive=true&continue=https://www.google.com/&ec=GAZAAQ; target=_top} @{innerHTML=; innerText=; outerHTML=; outerText=; tagName=A; aria-haspopup=true; id=gbg5; title=Options; class=gbgt; aria-owns=gbd5; href=http://www.google.com.tr/preferences?hl=tr} @{innerHTML=Search settings; innerText=Search settings; outerHTML=Search settings; outerText=Search settings; tagName=A; class=gbmt; href=/preferences?hl=tr} @{innerHTML=Web History; innerText=Web History; outerHTML=Web History; outerText=Web History; tagName=A; class=gbmt; href=http://www.google.com.tr/history/optout?hl=tr} @{innerHTML=Advanced search; innerText=Advanced search; outerHTML=Advanced search; outerText=Advanced search; tagName=A; href=/advanced_search?hl=tr&authuser=0} @{innerHTML=Advertisement; innerText=Advertisement; outerHTML=Ad; outerText=Advertisement; tagName=A; href=/intl/tr/ads/} @{innerHTML=Business Solutions; innerText=Business Solutions; outerHTML=Business Solutions; outerText=Business Solutions; tagName=A; href=http://www.google.com.tr/intl/tr/services/} @{innerHTML=About Google; innerText=About Google; outerHTML=About Google; outerText=About Google; tagName=A; href=/intl/tr/about.html} @{innerHTML=Google.com.tr; innerText=Google.com.tr; outerHTML=Google.com. tr; outerText=Google.com.tr; tagName=A; href=https://www.google.com/setprefdomain?prefdom=TR&prev=https://www.google.com.tr/&sig=K_EgsQi_VqHUnTVfTtru1YxCgPIis%3D} @{innerHTML=Privacy; innerText=Privacy; outerHTML=Privacy; outerText=Privacy; tagName=A; href=/intl/tr/policies/privacy/} @{innerHTML=Terms; innerText=Terms; outerHTML=Terms; outerText=Terms; tagName=A; href=/intl/tr/policies/terms/}
```

## Data Extraction

Sau khi phân tích nội dung HTML, chúng ta có thể trích xuất dữ liệu cần thiết. Ví dụ, để lấy phần **href** trong các liên kết (Links) hoặc **src** trong hình ảnh (Images), chúng ta có thể thực hiện như sau:

1. **Yêu cầu trang web và nhận phản hồi**:

   <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'
   </code></pre>
2. **Trích xuất chỉ các liên kết (href) và hình ảnh (src)**:

   <pre class="language-powershell" data-overflow="wrap"><code class="lang-powershell">Write-Host "----------------------------------------------"
   Write-Host "Links"
   Write-Host "----------------------------------------------"
   $response.Links.href  # Hiển thị chỉ phần href của từng liên kết

   Write-Host "----------------------------------------------"
   Write-Host "Images"
   Write-Host "----------------------------------------------"
   $response.Images.src  # Hiển thị chỉ phần src của từng ảnh
   </code></pre>

#### Giải thích

* **Links**: `$response.Links.href` sẽ chỉ xuất ra giá trị của thuộc tính **href** từ mỗi liên kết, thay vì xuất toàn bộ đối tượng chứa mã HTML phức tạp.
* **Images**: `$response.Images.src` sẽ chỉ lấy thuộc tính **src** của từng hình ảnh trong trang, giúp dễ dàng lấy URL của hình ảnh mà không cần xử lý mã HTML đầy đủ.

#### Kết quả

Khi chạy script, bạn sẽ thấy các URL cho từng liên kết và ảnh, làm cho việc trích xuất dữ liệu dễ dàng và gọn gàng hơn.

<figure><img src="/files/uM9a5aJ0V6HKzwVjwN28" alt=""><figcaption></figcaption></figure>

Nếu dữ liệu cần tìm nằm trong **Content** (tức là không được lưu trong các trường đặc biệt của đối tượng **BasicHtmlWebResponseObject**), ta có thể sử dụng **Regex** để tìm nội dung đó.

Dưới đây là ví dụ tìm nội dung của các thẻ `<span>` trong trường **Content** của phản hồi:

{% code overflow="wrap" %}

```powershell
$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'

# Sử dụng Regex để tìm nội dung của thẻ span
if ($response.Content -match "<span.*?>(.*?)</span>") {
    $matches[1]  # Nội dung tìm thấy sẽ được lưu trong $matches[1]
}
```

{% endcode %}

#### Giải thích

* **Regex `<span.*?>(.*?)</span>`**: Câu lệnh này tìm tất cả các thẻ `<span>` và trích xuất nội dung bên trong. Ký tự `.*?` giúp Regex dừng lại ngay khi tìm thấy dấu đóng `>`, và `(.*?)` là một nhóm bắt (capture group) để lấy nội dung giữa thẻ mở `<span>` và thẻ đóng `</span>`.
* **$matches\[1]**: Khi Regex tìm thấy khớp (match), nội dung bên trong thẻ `<span>` sẽ nằm trong `$matches[1]`.

#### Kết quả

Khi chạy script, nếu có bất kỳ nội dung nào nằm giữa các thẻ `<span>`, nó sẽ được in ra màn hình.

<figure><img src="/files/TQCiFFpn4sN7g0fePYlm" alt=""><figcaption></figcaption></figure>

Điều đáng chú ý là chúng ta chưa từng định nghĩa biến `$matches` trong quá trình thực hiện, nhưng vẫn có thể sử dụng biến này để lấy kết quả tìm kiếm thông qua `$response -match`.

Điều này là do `$matches` là một biến tự động trong PowerShell. Biến này tự động lưu trữ kết quả của các phép so khớp regex (`-match` và `-notmatch`) được thực hiện ngay trước đó.

Nhờ đó, chúng ta có thể truy cập nội dung trang web như các tiêu đề, hình ảnh, và liên kết, dễ dàng tìm kiếm trong các dữ liệu này để lấy thông tin mong muốn. Sau khi truy xuất dữ liệu, bước tiếp theo là làm sạch và lưu trữ dữ liệu.

## Refining and Storaging the Data

Dữ liệu đã trích xuất thường cần được tinh chỉnh (ví dụ, loại bỏ các khoảng trắng hoặc ký tự đặc biệt không cần thiết) và lưu trữ đúng cách (ví dụ, ghi vào tệp CSV hoặc cơ sở dữ liệu).

Tiếp tục với ví dụ trên, chúng ta đã liệt kê các liên kết trong phản hồi. Giờ đây, chúng ta sẽ chỉ trích xuất các phần FQDN, không phải toàn bộ liên kết, và ghi kết quả vào tệp.

Để bắt đầu, chúng ta cần trích xuất các FQDN từ URL từ thuộc tính `href`. Ví dụ, cần lấy phần `accounts.google.com` từ một URL như `https://accounts.google.com/ServiceLogin?hl=tr&amp;passive=true`.

Có nhiều cách để làm điều này; ví dụ, chúng ta có thể sử dụng regex hoặc dùng các hàm chuỗi để lấy phần giữa “**https\://**” và “**/**”.

Đầu tiên, chúng ta sẽ sử dụng kiểu dữ liệu **Uri** của .NET và trích xuất FQDN bằng cách truy cập thuộc tính `Host` của đối tượng **Uri**:

{% code overflow="wrap" %}

```powershell
$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'
foreach ($link in $response.links.href) {
    ([System.Uri]$link).Host
}
```

{% endcode %}

Dữ liệu từ cmdlet `Invoke-WebRequest` được gán vào biến `$response`. Sau đó, chúng ta bắt đầu một vòng lặp để gán từng giá trị `href` của mỗi liên kết trong biến `$response` vào biến `$link`.

Trong vòng lặp này, chúng ta biến mỗi giá trị `$link` thành một đối tượng Uri với `[System.Uri]$link`.

Một đối tượng **Uri** sẽ trông như sau:

<figure><img src="/files/Rq7xLuBg1xpxxaKrCw3M" alt=""><figcaption></figcaption></figure>

Trong danh sách này, thuộc tính `OriginalString` chứa URL trong biến `$link`. Khi chúng ta chuyển chuỗi này sang kiểu **Uri**, một bảng **HashTable** được tạo ra bằng cách tính toán các trường khác như đã thấy trong ảnh chụp màn hình trên. Chúng ta cần lấy thuộc tính `Host` trong số đó.

Chúng ta có thể in giá trị này ra màn hình bằng cách sau:

```powershell
([System.Uri]$link).Host
```

**Thực hiện tương tự với REGEX:**

Lần này, đầu tiên chúng ta tạo một mảng tên là `$links`. Sau đó, chúng ta cho mỗi URL trong bảng `Links` của đối tượng `$response` đi qua một mẫu REGEX với hàm `-match`, và thêm kết quả vào mảng `$links` vừa tạo. Cuối cùng, chúng ta in nội dung của mảng `$links` ra màn hình.

**Lưu ý:** `$links` mà chúng ta tạo và thuộc tính `Links` của đối tượng `$response` là hai thứ khác nhau.

```powershell
$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'

$links = @()

foreach ($link in $response.links.href) {
    $link -match '(?<=\/\/)[^\/]+(?=\/)'
    $links += ($matches[0])
}
$links
```

**Lưu dữ liệu vào tệp:**

Chúng ta có thể chuyển đổi dữ liệu sang định dạng phù hợp bằng các cmdlet như `ConvertTo-Csv`, `ConvertTo-Xml`, `ConvertTo-Html`, hoặc `ConvertTo-Json`, và ghi kết quả vào tệp.

Ví dụ, chuyển đổi đầu ra sang định dạng JSON và lưu vào tệp `links.json`:

```powershell
$response = Invoke-WebRequest -Uri "https://google.com" -Method 'GET'

$links = @()

foreach ($link in $response.links.href) {
    $link -match '(?<=\/\/)[^\/]+(?=\/)'
    $links += ($matches[0])
}
$links | ConvertTo-Json | Set-Content -Path "links.json"
```

Trong ví dụ này, chúng ta đã chuyển đổi đầu ra sang định dạng JSON và sau đó lưu vào tệp `links.json`.

<figure><img src="/files/1WqIXiCsg8BjMexTsYjU" alt=""><figcaption></figcaption></figure>

Chúng ta đã ghi dữ liệu thu được trong ví dụ của mình vào một tệp văn bản ở định dạng JSON. Tùy thuộc vào yêu cầu của ứng dụng, bạn cũng có thể ghi dữ liệu này vào một không gian đĩa ở vị trí từ xa, gửi qua FTP, ví dụ, hoặc ghi nó vào cơ sở dữ liệu.

## **Invoke-RestMethod**

Trong thế giới phần mềm ngày nay, một phần lớn các dịch vụ web hoạt động sử dụng REST APIs.

`Invoke-RestMethod` là một cmdlet cơ bản hoạt động với logic tương tự như `Invoke-WebRequest`. Sự khác biệt của nó là cung cấp các tùy chọn hỗ trợ khác nhau giúp dễ dàng thực hiện các thao tác với dịch vụ REST API.

Điều quan trọng nhất trong các hỗ trợ này là `Invoke-RestMethod` tự động phân tích phản hồi. Ví dụ, nó tự động chuyển đổi dữ liệu JSON thành các đối tượng PowerShell. Chúng ta hãy kiểm tra một ví dụ để hiểu rõ hơn:

{% code overflow="wrap" %}

```powershell
$response = Invoke-WebRequest -Uri "https://my-json-server.typicode.com/typicode/demo/comments"
$response

Write-Host "---------------------------------------------- --"
$response = Invoke-RestMethod -Uri "https://my-json-server.typicode.com/typicode/demo/comments"
$response

Write-Host "---------------------------------------------- --"
$response = Invoke-RestMethod -Uri "https://my-json-server.typicode.com/typicode/demo/comments"
$response.body
```

{% endcode %}

Trong đoạn mã của chúng ta, đầu tiên, chúng ta gọi cùng một URL với phương thức `Invoke-WebRequest`. Sau đó, chúng ta gọi nó với cmdlet `Invoke-RestMethod` và ghi toàn bộ đối tượng phản hồi ra màn hình. Cuối cùng, chúng ta gọi cùng một URL với `Invoke-RestMethod` và chỉ ghi các trường "body" trong phản hồi ra màn hình.

Kết quả đầu ra của chúng ta sẽ như sau:

<figure><img src="/files/rp3cJS7aZm0B9NRO0tHZ" alt=""><figcaption></figcaption></figure>

Như bạn thấy, chúng ta có thể sử dụng phản hồi ở định dạng JSON trả về từ một yêu cầu GET đến dịch vụ REST như một đối tượng PowerShell mà không cần xử lý thêm.

#### **Danh sách các tham số bạn có thể sử dụng với `Invoke-RestMethod`**:

<figure><img src="/files/LA4NsWNwmVLDxAQpkRb2" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/AT2kevVEglnBL1zyOvkd" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/cTNXsZTg6wRvrrSNe8VE" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/7fW82Mdk2OhXsE4BjdeS" alt=""><figcaption></figcaption></figure>

#### **Xử lý Lỗi trong Web Scraping với PowerShell**

Như với bất kỳ kịch bản PowerShell nào, việc xử lý lỗi cũng rất quan trọng trong các kịch bản web scraping. Bạn có thể sử dụng các khối `Try/Catch` để bắt các lỗi tiềm ẩn và xử lý chúng một cách thích hợp.

Chúng ta đã đề cập đến chủ đề này trong các khóa đào tạo PowerShell trước. Nếu bạn không nhớ chi tiết về cách sử dụng các khối `Try/Catch`, đây là thời gian để quay lại và ôn lại để củng cố kiến thức của mình. Bạn có thể truy cập khóa đào tạo liên quan thông qua liên kết dưới đây:

**Quản lý Lỗi: Tối ưu hóa và Quản lý Lỗi**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/education/window-pe-.net/powershell/powershell-for-analysis/web-scraping.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
