tjw-bk

多线程爬虫


今日内容

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

分类:

技术点:

相关文章: