zoukankan      html  css  js  c++  java
  • python-爬虫 多线程爬虫

    多线程爬虫


    今日内容

    1. 并发与并行(**)
    2. 多线程导致数据的不安全(**) --> 理解不了, 那就记住结论(多线程共同操作数据会导致数据不安全)
    3. 多线程爬虫架构(*****)
    4. 多线程爬虫的代码(*****)
    

    1.并发与并行

    1.并发: 在同一时间段内, 所有任务同时运行.
    2.并行: 在同一时刻, 所有任务同时执行
    

    2.多线程

    i = 0
    i += 1
    i -= 1
    print(i)
    多线程共同操作数据会导致数据不安全
    

    3.多线程架构图

    1.url,发请求, 获取响应
    2.数据解析
    3.数据持久化
    

    from threading import Thread
    from threading import Lock
    from queue import Queue
    import requests
    import pymysql
    from lxml import etree
    
    
    # base_url = 'http://xiaohua.zol.com.cn/youmo/%s.html'
    # 爬虫类
    class Sqider(Thread):
        def __init__(self, sname, urlQueue, dataQueue):
            super().__init__()
            self.sname = sname
            self.urlQueue = urlQueue
            self.dataQueue = dataQueue
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36'
            }
    
        # 爬取数据
        def run(self, ):
            base_url = 'http://xiaohua.zol.com.cn/youmo/%s.html'
    
            while 1:
                # block 代表阻塞,block为True即为阻塞。block为False为不阻塞
                try:
                    print('%s正在爬取数据' % self.name)
                    page = self.urlQueue.get(block=False)
                    res = requests.get(url=base_url % page, headers=self.headers)
                    self.dataQueue.put(res.text)
                    print('%s提交数据完毕--' % self.name)
                except:
                    break
    
    
    # 解析类
    class Parse(Thread):
        def __init__(self, pname, dataQueue, conn, cursor, lock):
            super().__init__()
            self.pname = pname
            self.dataQueue = dataQueue
            self.conn = conn
            self.cursor = cursor
            self.lock = lock
    
        def run(self):
            # 实现数据解析的过程
            print('run方法已经调用')
            self.parse(self.dataQueue)  # 调用parse方法
    
        def parse(self, dQueue):
            # 实现具体的解析过程
            while 1:
                try:
                    html = dQueue.get()
                    tree = etree.HTML(html)
                    li_list = tree.xpath('//li[@class="article-summary"]')
                    for li in li_list:
                        title = li.xpath('.//span[@class="article-title"]/a/text()')[0]
                        content = li.xpath('.//div[@class="summary-text"]//text()')
    
                        data = {'title': title, 'content': content}
                        with self.lock:
                            self.save(data)
                except:
                    break
    
        # 存储数据
        def save(self, data):
            sql = 'insert into joke values ("%s","%s")' % (data['title'], data['content'])
            try:
                self.cursor.execute(sql)
                self.conn.commit()
                print('%s存储数据成功' % self.pname)
    
            except Exception as e:
                print(e)
                self.conn.rollback()
    
    
    # 主函数
    def main():
        # 盛放url的地方 url队列
        urlQueue = Queue()
        for page in range(1, 101):
            urlQueue.put(page)
    
        # 放置响应数据
        dataQueue = Queue()
    
        # 开启爬虫线程
        snames = ['爬虫1号', '爬虫2号', '爬虫3号']
        slist = []
        for sname in snames:
            # 实例化线程对象
            s = Sqider(sname, urlQueue, dataQueue)
    
            # 开启线程
            s.start()
            slist.append(s)
        for s in slist:
            s.join()
    
        # 链接数据库
        conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', charset='utf8',
                               database='xiaohua')
        cursor = conn.cursor()
    
        # 解析线程的开启
        lock = Lock()  # 上锁
        plist = []
        pnl = ['解析1号', '解析2号', '解析3号']
        for pname in pnl:
            p = Parse(pname, dataQueue, conn, cursor, lock)
            p.start()
            plist.append(p)
        for p in plist:
            p.join()
    
    
    # 程序入口
    if __name__ == '__main__':
        main()
    
    
    从小白到大神的蜕变~~
  • 相关阅读:
    Asp.Net Winform 条形码系列之Code39 Code39 Of .Net BarCode Serial Blog
    .NET 中文星期几的简单实现方式
    C#使用SQLite数据库(asp.net/winform)
    .Net日期时间格式化输出大全 DateTime.ToString(?)
    C#使用HTTP头检测网络资源是否有效
    [转]C#(VB.NET)操作Windows自带的防火墙 之 添加/删除允许通过防火墙的例外程序
    华为C2800进入工程模式
    android webview 加载网页显示对话框
    SVN 与 VS2003
    VisualSVN1.7.7 序列号
  • 原文地址:https://www.cnblogs.com/tjw-bk/p/13752023.html
Copyright © 2011-2022 走看看