Loading

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

posted @ 2020-09-29 21:28  就学45分钟  阅读(280)  评论(0编辑  收藏  举报