天天看點

簡單爬蟲+ 線程+SQL+網頁多線程實作簡單的爬蟲儲存在字典中(電影天堂)爬取電影資訊儲存在資料庫中将爬取的電影資訊展示到網頁中

文章目錄

  • 多線程實作簡單的爬蟲儲存在字典中(電影天堂)
  • 爬取電影資訊儲存在資料庫中
  • 将爬取的電影資訊展示到網頁中

多線程實作簡單的爬蟲儲存在字典中(電影天堂)

=============================使用多線程得到下載下傳的電影位址(沒有使用的時候,很慢)==================================
import re
import urllib.request
import time
import threading

class Spider(object):
    def __init__(self):
        self.film_dict = {} # 定義字典存儲下載下傳的影片資訊
        self.i = 1 # 檢視擷取影片的數量
        self.lock1 = threading.Lock() # 互斥的寫入字典
    def start(self):
        # 設定多線程,爬蟲多個頁面清單
        for page in range(1,4):
            t1 = threading.Thread(target=self.get_movie_link, args=(page,))
            t1.start()
        #  得到字典對應的數組
        list1 = self.film_dict.items()
        # 所有線程執行完畢後再退出
        while len(threading.enumerate()) != 1:
            time.sleep(1)
        # 周遊下載下傳字典,擷取影片名稱、下載下傳位址
        for film_name, film_download_url in list1:
            print(film_name, "|", film_download_url)

    def get_movie_link(self, page):
        #設定要爬的電影清單url
        film_list_url = "https://www.ygdy8.net/html/gndy/dyzz/list_23_%d.html" % page
        # 打開url ,擷取資料 <http.client.HTTPResponse object at 0x000002596CA13400>
        response_list = urllib.request.urlopen(film_list_url)
        # 讀取清單傳回的資料
        response_list_data = response_list.read()
        # 解碼資料
        response_list_text = response_list_data.decode("gb2312", "ignore")#輸出的就是右擊檢視網頁源代碼的内容
        # 使用正則比對獲得每一條的電影名和相應連結
        # <a href="/html/gndy/dyzz/20200809/60326.html" target="_blank" rel="external nofollow"  class="ulink">2020年奇幻劇情《秘密花園》BD中英雙字幕</a>
        url_list = re.findall("<a href=\"(.*)\" class=\"ulink\">(.*)</a>", response_list_text)
        # url_list 是清單,每一個元素是元組
        # [('/html/gndy/dyzz/20200809/60326.html', '2020年奇幻劇情《秘密花園》BD中英雙字幕'),
        # ('/html/gndy/dyzz/20200809/60325.html', '2020年劇情傳記《放射性物質》BD中英雙字幕')..]
        for film_content_url, film_name in url_list:
            film_content_url = "https://www.ygdy8.net" + film_content_url
            #  打開電影的url位址
            response_content = urllib.request.urlopen(film_content_url)
            response_content_data = response_content.read()
            response_content_text = response_content_data.decode("gb2312", "ignore")
            # 使用正則 取出下載下傳位址
            ret = re.search("bgcolor=\"#fdfddf\"><a href=\"(.*?)\">", response_content_text)
            if ret:
                # 儲存影片名稱和下載下傳位址到字典中
                self.lock1.acquire()
                self.film_dict[film_name] = ret.group(1)
                self.lock1.release()
                print("已經成功爬取 %d 個影片位址!" % self.i)
                self.i += 1
            else:
                continue
def main():
    film_spider = Spider()
    film_spider.start()

if __name__ == '__main__':
    main()
  
#注意:如果沒有‘ignore’會報錯 
#UnicodeDecodeError: 'gb2312' codec can't decode byte 0xa9 in position 11775: illegal multibyte sequence  
#是以使用ignore 忽略非 gb2321編碼的字元
           
簡單爬蟲+ 線程+SQL+網頁多線程實作簡單的爬蟲儲存在字典中(電影天堂)爬取電影資訊儲存在資料庫中将爬取的電影資訊展示到網頁中

爬取電影資訊儲存在資料庫中

首先建立資料庫和存儲電影資訊的表

create database movie_db charset=utf8; # 建立資料庫
use movie_db; # 選擇資料庫
# 建立資料表
create table movie_link(
id int(11) primary key auto_increment,
film_name varchar(255) not null,
film_link varchar(255) not null
)charsset=utf8;
           
=====================簡單爬取電影資訊插入到資料庫中,重複的資料不插入=============================================
import re
import urllib.request
from pymysql import connect


def add_film(film_name, film_link):
    """ 定義專門的函數,儲存影片資訊到資料庫中(插入)"""
    sql ="insert into movie_link values(null, %s, %s)"
    ret = cur.execute(sql, [film_name, film_link])
    # 如果插入成功,給出提示
    if ret:
        print("儲存成功!影片[%s]" % film_name)

def film_exist(film_name, film_link):
    """定義專門的函數,檢測資料是否已經存在(查詢)"""
    sql = "select id from movie_link where film_name=%s and film_link=%s limit 1"
    ret = cur.execute(sql,[film_name, film_link])
    #如果擷取的記錄數 >0 傳回真
    if ret:
        return True
    else:
        return False


def get_movie_links():
    """擷取清單頁影片資訊"""
    # 1.定義清單的位址
    film_list_url = "https://www.ygdy8.net/html/gndy/dyzz/list_23_1.html"

    # 2.打開url位址,擷取資料  <http.client.HTTPResponse object at 0x0000026B03B4EC50>
    response_list = urllib.request.urlopen(film_list_url)

    # 2.1通過read()讀取網絡資源資料
    response_list_data = response_list.read()

    # 3.解碼擷取到的内容
    response_list_text = response_list_data.decode("gb2312", "ignore")

    # 4.使用正則得到所有的影片内容位址
    #print(response_list_text) #輸出的就是右擊檢視網頁源代碼的内容

    # 4.1 使用findall()根據正則查找所有影片對應的内容也位址
    url_list = re.findall(r"<a href=\"(.*)\" class=\"ulink\">(.*)</a>", response_list_text)
    # 4.2儲存位址
     # [('/html/gndy/dyzz/20200809/60326.html', '2020年奇幻劇情《秘密花園》BD中英雙字幕'),
    # ('/html/gndy/dyzz/20200809/60325.html', '2020年劇情傳記《放射性物質》BD中英雙字幕')..]
    #print(url_list)# 以上用清單包起來,每一個是元組

    # 定義一個字典,用于儲存影片資訊
    films_dict = {}
    # 計數
    i = 1
    # 循環周遊 url_list
    for content_url, film_name in url_list:
        # 電影的url位址是:https://www.ygdy8.net/html/gndy/dyzz/20200809/60326.html
        content_url = "https://www.ygdy8.net" + content_url

        # 打開内容頁位址
        response_content = urllib.request.urlopen(content_url)
        # 接收内容頁資料
        response_content_data = response_content.read()
        # 解碼得到内容頁的文本内容
        response_content_text = response_content_data.decode("gb2312", "ignore")
        #print(response_content_text)
        # 取出下載下傳位址
        result = re.search(r"bgcolor=\"#fdfddf\"><a href=\"(.*?)\">",response_content_text)
        if result:
            films_dict[film_name] = result.group(1)
            print("已經擷取 %d 條資訊" % i)
            i += 1
        else:
            break
    return films_dict

def main():
    film_dict = get_movie_links()
    # 周遊字典
    for film_name, film_link in film_dict.items():
        # 如果資料庫中存在相同的資料就不再插入
        if film_exist(film_name, film_link):
            print("儲存失敗!影片:[%s]" % film_name)
            continue
        # 調用函數儲存資料
        add_film(film_name, film_link)
if __name__ == '__main__':
    # 建立連接配接對象
    conn = connect(host="localhost", user="root", password="mysql", database="movie_db")
    # 建立遊标對象
    cur = conn.cursor()
    # 調用爬出資料的函數
    main()
    # 送出資料
    conn.commit()
    # 關閉遊标
    cur.close()
    # 關閉連接配接
    conn.close()


           
簡單爬蟲+ 線程+SQL+網頁多線程實作簡單的爬蟲儲存在字典中(電影天堂)爬取電影資訊儲存在資料庫中将爬取的電影資訊展示到網頁中

将爬取的電影資訊展示到網頁中

參考 實作簡單的web伺服器并傳回 固定資料 (頁面)給浏覽器

思路:把原本固定的内容變為從資料庫動态讀取

================将傳回的固定内容,變成從資料庫讀取的内容,拼接在一起,形成新的response_body===========================
import socket
import pymysql


def request_handler(new_client_socket, ip_port):
    # 接收用戶端浏覽器發送的協定
    request_data = new_client_socket.recv(1024)
    # 判斷協定是否為空
    if not request_data:
        print("%s 用戶端已經下線!" % str(ip_port))
        new_client_socket.close()
        return
    # 拼接響應封包
    response_line = "HTTP/1.1 200 OK\r\n"
    response_header = "Server:Python20WS/2.1\r\n"
    response_header += "Content-type:text/html;charset=utf-8\r\n" # 防止亂碼,以html頁面顯示
    response_blank = "\r\n"


    response_body = " "
    # 連接配接資料庫
    conn = pymysql.connect(host="localhost", user="root", password="mysql",database="movie_db")
    # 建立遊标
    cur = conn.cursor()
    sql = "select * from movie_link order by id desc"
    cur.execute(sql)
    result_list = cur.fetchall() #擷取執行結果的所有内容((1, 'film_name', 'film_link'),(... ).....)
    # 周遊每一個元組
    for row in result_list:
        response_body += "%d.%s  下載下傳位址:[<a href='%s'>%s</a>] <br>" % (row[0], row[1], row[2], row[2])

    # 關閉操作
    cur.close()
    conn.close()

    response_data = response_line + response_header + response_blank + response_body
    # 發送響應封包
    new_client_socket.send(response_data.encode())
    # 關閉套接字
    new_client_socket.close()
def main():
    # 建立套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 設定位址重用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, True)
    # 綁定端口
    tcp_server_socket.bind(("", 8080))
    # 設定監聽,讓套接字由主動變為被動
    tcp_server_socket.listen(128)
    while True:
        # <socket.socket fd=500, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.1.26.31', 8080), raddr=('10.1.26.31', 64089)>
        # ('10.1.26.31', 64089) 當有用戶端連接配接的話傳回新的socket對象,和ip位址,端口号
        new_client_socket, ip_port = tcp_server_socket.accept()
        print(" 新客戶來了:", ip_port)
        # 接收資訊并作出響應
        request_handler(new_client_socket, ip_port)
    # 關閉套接字
    tcp_server_socket.close()
if __name__ == '__main__':
    main()
           
簡單爬蟲+ 線程+SQL+網頁多線程實作簡單的爬蟲儲存在字典中(電影天堂)爬取電影資訊儲存在資料庫中将爬取的電影資訊展示到網頁中