简单爬虫+ 线程+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" 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编码的字符

在这里插入图片描述

爬取电影信息保存在数据库中

首先创建数据库和存储电影信息的表

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()


在这里插入图片描述

将爬取的电影信息展示到网页中

参考 实现简单的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()

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个开源的Java开发框架,它简化了Spring应用程序的配置和部署过程。它提供了一种快速开发和部署应用程序的方式,提升了开发效率。 WebMagic是一个开源的Java框架,用于爬取互联网上的数据。它基于WebMagic的核心思想,提供了一种简单易用的方式来爬取网页,并且支持多线程和分布式爬取。WebMagic可以快速构建Web爬虫,获取目标网站上的数据。 Mybatis是一个流行的Java持久化框架,它提供了一种简单易用的方式来访问关系型数据库。Mybatis通过将SQL语句与Java代码进行解耦,实现了数据持久化的功能。它支持自定义SQL语句、事务管理、缓存等功能,方便开发者处理数据库操作。 当我们结合使用Spring Boot、WebMagic和Mybatis时,可以实现一个完整的Web爬虫应用程序。 首先,我们可以使用Spring Boot来搭建应用程序的基础框架,包括配置文件、依赖管理、日志等,简化了应用程序的开发和部署过程。 然后,我们可以使用WebMagic来实现爬取网页的功能。通过定义爬取规则和处理器,可以指定要爬取的网页和提取出的数据。WebMagic支持多线程和分布式爬取,可以提高数据爬取的效率和速度。 最后,我们可以使用Mybatis来实现数据持久化的功能。通过定义Mapper接口和XML文件,我们可以将数据库操作与Java代码解耦,实现数据的增删改查。 综上所述,结合Spring Boot、WebMagic和Mybatis,我们可以构建一个功能强大的Web爬虫应用程序。这个应用程序可以快速爬取网页数据,并将数据存储到数据库中,为我们提供方便快捷的数据访问和处理方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值