<jupyter_start><jupyter_text>Lab02: Web Crawler (Continue).- MSSV: 1712282- Họ và tên: LÊ ĐOÀN CÔNG ẢNH  Yêu cầu bài tập**Cách làm bài**Bạn sẽ làm trực tiếp trên file notebook này; trong file, từ `TODO` để cho biết những phần mà bạn cần phải làm.Bạn có thể thảo luận ý tưởng cũng như tham khảo các tài liệu, nhưng *code và bài làm phải là của bạn*. Nếu vi phạm thì sẽ bị 0 điểm cho bài tập này.**Cách nộp bài**Trước khi nộp bài, rerun lại notebook (`Kernel` -> `Restart & Run All`).Bạn nộp file notebook với tên `MSSV.ipynb` của bạn (vd, nếu bạn có MSSV là 1234567 thì bạn đặt tên file là `1234567.ipynb`) và nộp file này trên moodle.**Nội dung bài tập**Thu thập và thể hiện dữ liệu web.  2. Cài đặt  2.1. Import library<jupyter_code>import requests
import re
from bs4 import BeautifulSoup
from bs4.element import Comment
import string<jupyter_output><empty_output><jupyter_text>2.2. HTML Parser Bộ phân tích cú pháp HTML (HTML Parser): nhận HTML code và trích xuất thông tin liên quan như tiêu đề của trang, đoạn văn trong trang, tiêu đề trong trang, liên kết, văn bản in đậm, v.v.<jupyter_code>from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Start tag:", tag)

    def handle_endtag(self, tag):
        print("End tag :", tag)

    def handle_data(self, data):
        print("Data  :", data)

parser = MyHTMLParser()
parser.feed('<html><head><title>Test</title></head>')<jupyter_output>Start tag: html
Start tag: head
Start tag: title
Data  : Test
End tag : title
End tag : head<jupyter_text>Loại bỏ các HTML tag không cần thiết bằng cách thiết lập filter<jupyter_code>def text_filter(element):
    if element.parent.name in ['style', 'title', 'script', 'head', '[document]', 'class', 'a', 'li']:
        return False
    elif isinstance(element, Comment):
        '''Opinion mining?'''
        return False
    elif re.match(r"[\s\r\n]+",str(element)): 
        '''space, return, endline'''
        return False
    return True<jupyter_output><empty_output><jupyter_text>2.3 Thu thập nội dung trang Web  Trong bài tập này ta thể hiện tài liệu (hay nội dung trang web) với cấu trúc đơn giản như sau: - Gọi $D$ là một tập tài liệu chứa *n* tài liệu: $D=\left\{d_1,d_2,...,d_n\right\}$.- Ta thể hiện tài liệu bằng một dictionary `data={}` với `data[word]=[[url_idx_1,url_idx_2,...],frequency]` với `url_index`$\in{\left[{1,n}\right]}$VD: `data['at']=[[1,2], 5]`Từ `at` xuất hiện trong đường dẫn có index `1` và `2` tổng số lần xuất hiện là 5.  Bước 1: liệt kê các từ xuất hiện trong trang web:<jupyter_code>def wordList(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.content, "html.parser")
    text = soup.findAll(text=True)
    filtered_text = list(filter(text_filter, text)) # list của các chuỗi
    word_list = []

    # TODO:
    # Với mỗi chuỗi trong filtered_text:
    #   Thay thế các dấu câu thành khoảng trắng (gợi ý: danh sách các dấu câu: string.punctuation; thay thế: .replace(...))
    #   Tách chuỗi bởi khoảng trắng (.split(...))
    #   Thêm các từ vừa được tách ra vào word_list
    
    # remove all punctuation in filered_text
    for i in range(len(filtered_text)):
        for ele in filtered_text[i]:
            if ele in string.punctuation:
                filtered_text[i] = filtered_text[i].replace(ele, " ")

            # remove '\n' from filtered_text
            filtered_text[i] = filtered_text[i].replace('\n', " ")
            filtered_text[i] = filtered_text[i].replace('–', " ")
            filtered_text[i] = filtered_text[i].replace('\xa0', " ")
    
    # split by ' ' from filtered_text
    for i in filtered_text:
        word_list += i.split(' ')

    # remove all element '' in word_list
    word_list = list(filter(lambda a: a != '', word_list))
    return word_list
  
# Test
print(wordList('https://en.wikipedia.org/wiki/Web_mining'))
# for i in wordList('https://en.wikipedia.org/wiki/Web_mining'):
#     print(i)<jupyter_output>['Web', 'mining', 'From', 'Wikipedia', 'the', 'free', 'encyclopedia', 'This', 'article', 'includes', 'a', 'related', 'reading', 'or', 'but', 'its', 'sources', 'remain', 'unclear', 'because', 'it', 'lacks', 'October', '2020', 'This', 'article', 'may', 'require', 'The', 'specific', 'problem', 'is', 'The', 'article', 'needs', 'sufficient', 'inline', 'references', 'and', 'a', 'complete', 're', 'write', 'has', 'been', 'proposed', 'October', '2020', 'Web', 'mining', 'As', 'the', 'name', 'proposes', 'this', 'is', 'information', 'gathered', 'by', 'mining', 'the', 'web', 'It', 'makes', 'utilization', 'of', 'automated', 'apparatuses', 'to', 'reveal', 'and', 'extricate', 'data', 'from', 'servers', 'and', 'web2', 'reports', 'and', 'it', 'permits', 'organizations', 'to', 'get', 'to', 'both', 'organized', 'and', 'unstructured', 'information', 'from', 'browser', 'activities', 'server', 'logs', 'website', 'and', 'link', 'structure', 'page', 'content', 'and', 'different', 'sources', 'The', 'goal', 'of'[...]<jupyter_text>Bước 2: Tính tần suất xuất hiện của từ trong 1 trang web, lưu trữ dữ liệu vào data:<jupyter_code>def read_url(url, url_idx, data):
    word_list = wordList(url)
    # TODO
    # Với mỗi từ w trong word_list:
    #   Nếu w chưa có trong data thì khởi tạo data[w] = [[url_idx], 1]
    #   Ngược lại thì thêm url_idx vào data[w][0] (nếu chưa có) và tăng data[w][1] lên 1 đơn vị
    
    for w in word_list:
        if w in data:
            data[w][1] += 1
            if not url_idx in data[w][0]:
                data[w][0].append(url_idx)
        else:
            data[w] = [[url_idx], 1]

# Test
test_data = {}
read_url('https://en.wikipedia.org/wiki/Web_mining', 1, test_data)
test_data<jupyter_output><empty_output><jupyter_text>Bước 3: Chạy chương trình lưu kết quả vào file output.txt<jupyter_code>data = {}
read_url('https://en.wikipedia.org/wiki/Web_mining', 1, data)
read_url('https://en.wikipedia.org/wiki/Data_mining', 2, data)

sorted_keys = sorted(data.keys())

with open("output.txt", "w", encoding="utf-8") as f:
    output_line = "Word".ljust(20) + "Frequency".ljust(15) + "URL_idx".ljust(15) + "\n"
    f.writelines(output_line)
    f.writelines('---------------------------------------------------------------------\n\n')
    for key in sorted_keys:
        output_string = str(key).ljust(20) + str(data[key][1]).ljust(15) + str(data[key][0]).ljust(15) + "\n"
        f.writelines(output_string)

# TODO
# Keyword tìm kiếm: python pickle
# Dùng pickle để lưu dictionary data xuống đĩa. Sau đó đọc lên và in ra 10 giá trị đầu tiên của nó.

# 1. Lưu data
import pickle
filename = 'pickle.txt'
outfile = open(filename,'wb')
pickle.dump(data, outfile)

# 2. Đọc lên và in ra
with open(filename, "rb") as f:
    db = pickle.load(f)
    k = 0
    for i in db:
        if k < 10:
            print(str(i).ljust(20) + " : " + str(db[i]))
        else:
            break
        k+=1<jupyter_output>Web                  : [[1, 2], 48]
mining               : [[1, 2], 95]
From                 : [[1, 2], 3]
Wikipedia            : [[1, 2], 2]
the                  : [[1, 2], 125]
free                 : [[1, 2], 3]
encyclopedia         : [[1, 2], 2]
This                 : [[1, 2], 12]
article              : [[1, 2], 5]
includes             : [[1], 1]
{'fraction_non_alphanumeric': 0.1688293760353396, 'fraction_numerical': 0.017807840971838764, 'mean_word_length': 3.204875217643645, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 28, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '203684', 'license': 'MIT', 'n_tokens_mistral': 3070, 'n_tokens_neox': 2982, 'n_words': 801, 'path': 'Lab-02/Lab02_WebCrawler.ipynb', 'repo_name': 'conganhhcmus/web-crawler', 'size': '7244'}