day05 -爬虫基本流程总结和嗅事百科单/多线程爬虫案列

一、基本流程总结
1.准备url

  • 准备start_url
    使用情况:url地址规律不明显,总数不确定
    具体做法:通过代码提取下一页的url,可通过 xpath 寻找url地址,部分参数在当前的响应中(比如,当前页码数和总的页码数在当前的响应中)

  • 准备url_list
    使用情况:页码总数明确,url地址规律明显

2.发送请求,获取响应

  • 反反爬虫
    (1)添加随机的User-Agent,反反爬虫
    (2)添加随机的代理ip,反反爬虫

:
①在对方判断出我们是爬虫之后,应该添加更多的headers字段,包括cookie( cookie的处理可以使用session来解决,requests.Session(),session.get(url))
②准备一堆能用的cookie,组成cookie池

  • 不登录请求
    (1)准备刚开始能够成功请求对方网站的cookie,即接收对方网站设置在response的cookie
    (2) 下一次请求的时候,使用之前的列表中的cookie来请求
  • 登录后的请求
    (1)准备多个账号
    (2)使用程序获取每个账号的cookie,之后请求登录之后才能访问的网站随机的选择cookie

3.提取数据

  • 如果数据不在当前的url的响应中
    • 确定数据的位置
      (1) 提取的是列表页的数据
      直接请求列表页的url地址,不用进入详情页
      (2) 提取的是详情页的数据
      .确定url
      .发送请求
      .提取数据
      .返回数据
  • 如果数据不在当前的url地址中- 在其他的响应中,寻找数据的位置(从其他url响应中查找数据)
    (1) 从network中从上往下找,并在响应数据中通过ctr+f过滤来查找
    (2)使用chrome中的过滤条件,选择出了js,css,img之外的按钮
    (3)使用chrome的search all file,搜索数字和英文
  • 提取数据的方式
    (1)xpath,从html中提取整块的数据,先分组,之后每一组再提取
    (2)re正则表达式,通过re.search/findall等匹配方式匹配爬取的数据
    (3json

4.保存

  • 保存在本地,text,json,csv
  • 保存在数据库

二、单线程爬取嗅事百科段子案例

  • 爬取嗅事百科段子每一页上,每条帖子的发帖人昵称,性别,年龄,发帖内容,帖子好笑数
import requests
from lxml import etree
import json

class XiuBai():
    
    def __init__(self):
        self.url_list = ['http://www.qiushibaike.com/text/page/%d/'%i for i in range(1,14)]
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'} 
        
    
    def parse_url(self,url):
        '''发送请求,获取响应'''
        print(url)
        response = requests.get(url,headers=self.headers)
#         print(response.content.decode())
        return response.content.decode()     # 返回字符串类型
            
    def get_content(self,html_str):
        '''提取数据(使用xpath方式提取)'''
        content_list = []      # 用于存储每一页的所有帖子内容
        #创建element对象
        html = etree.HTML(html_str)   
        # 分组,每个div是一条帖子,返回列表类型
        div_list = html.xpath("//div[@class='col1 old-style-col1']/div")   
        # 遍历每一条帖子div
        for div in div_list:
            # 将每条帖子的相关内容存储在字典中
            item = {}
            #1.提取每个发帖人的昵称
            item['name'] = div.xpath('./div[@class="author clearfix"]//img/@alt')
            item['name'] =  item['name'][0] if len(item['name'])>0 else None 
             #2.提取每个发帖人的年龄
            item['age'] = div.xpath('./div[@class="author clearfix"]/div/text()')
            item['age'] =   item['age'][0] if len(item['age'])>0 else None
            #3.提取每个发帖人的性别
            item['gender'] = div.xpath('./div[@class="author clearfix"]/div/@class')
            item['gender'] = item['gender'][0].split(' ')[-1].replace('Icon','') if len(item['gender'])> 0 else None
            #4.提取每个帖子的内容
            item['content'] = div.xpath('./a/div[@class="content"]/span/text()')
            item['content'] = item['content'][0].replace(r'\n','') if len(item['content'])> 0 else None
            #5.提取每个帖子中的好笑数
            item['smlie_num'] = div.xpath('./div[@class="stats"]//i[@class="number"]/text()') 
            item['smlie_num'] =  item['smlie_num'][0] if len(item['smlie_num'])> 0 else None
            content_list.append(item)        
        return content_list
           
    def save_file(self,content):
        '''保存数据'''
        with open('qiubai.txt','a',encoding='utf-8',newline='') as f:
            f.write(json.dumps(content,ensure_ascii=False,indent=2))
            f.write('\n')
    
    def run(self):
        '''完成整体的控制'''
        #1. 创建url列表
        for url in self.url_list:
        #2.发送请求,获取响应
            html_str = self.parse_url(url)        
        #3.提取数据
            content_list = self.get_content(html_str)
        #4.保存数据
            self.save_file(content_list)

xiubai = XiuBai()
xiubai.run()      

qiubai.txt

在这里插入图片描述
三、多线程爬取数据

在这里插入图片描述

  • 使用Thread实现多线程发送请求,提取数据
  • 使用Queue队列实现对线程间的通信
import requests
from lxml import etree
import json
import threading
from queue import Queue

class XiuBai():
    
    def __init__(self):
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'} 
        self.start_url = 'http://www.qiushibaike.com/text/page/{}/'
        self.url_queue = Queue()
        self.html_queue = Queue()
        self.content_queue = Queue()
        
        
    def create_url_list(self):
        '''创建url列表'''
        for i in range(1,14):
            # 将url保存在self.url_queue队列中
            self.url_queue.put(self.start_url.format(i))
    
    def parse_url(self):
        '''发送请求,获取响应'''
        while True:
            #将url从队列Q中取出
            url = self.url_queue.get() 
            print(url)
            response = requests.get(url,headers=self.headers)
            # 将响应数据保存在队列中
            self.html_queue.put(response.content.decode())     
            self.url_queue.task_done()
            
    def get_content(self):
        '''提取数据(使用xpath方式提取)'''
        while True:
            # 将相应数据从队列Q中取出
            html_str = self.html_queue.get()
            content_list = []      # 用于存储每一页的所有帖子内容
            #创建element对象
            html = etree.HTML(html_str)   
            # 分组,每个div是一条帖子,返回列表类型
            div_list = html.xpath("//div[@class='col1 old-style-col1']/div")   
            # 遍历每一条帖子div
            for div in div_list:
                # 将每条帖子的相关内容存储在字典中
                item = {}
                #1.提取每个发帖人的昵称
                item['name'] = div.xpath('./div[@class="author clearfix"]//img/@alt')
                item['name'] =  item['name'][0] if len(item['name'])>0 else None 
                 #2.提取每个发帖人的年龄
                item['age'] = div.xpath('./div[@class="author clearfix"]/div/text()')
                item['age'] =   item['age'][0] if len(item['age'])>0 else None
                #3.提取每个发帖人的性别
                item['gender'] = div.xpath('./div[@class="author clearfix"]/div/@class')
                item['gender'] = item['gender'][0].split(' ')[-1].replace('Icon','') if len(item['gender'])> 0 else None
                #4.提取每个帖子的内容
                item['content'] = div.xpath('./a/div[@class="content"]/span/text()')
                item['content'] = item['content'][0].replace(r'\n','') if len(item['content'])> 0 else None
                #5.提取每个帖子中的好笑数
                item['smlie_num'] = div.xpath('./div[@class="stats"]//i[@class="number"]/text()') 
                item['smlie_num'] =  item['smlie_num'][0] if len(item['smlie_num'])> 0 else None
                content_list.append(item)  
            # 将数据存在self.content_queue队列中
            self.content_queue.put(content_list)
            self.html_queue.task_done()
           
    def save_file(self):
        '''保存数据'''
        while True:
            with open('qiubai.txt','a',encoding='utf-8',newline='') as f:
                # 将数据从队列Q中取出
                content = self.content_queue.get()
                f.write(json.dumps(content,ensure_ascii=False,indent=2))
                f.write('\n')
                self.content_queue.task_done()
    
    def run(self):
        '''完成整体的控制'''
        thread_list = []
        #1. 创建url列表
        url_th = threading.Thread(target=self.create_url_list) 
        thread_list.append(url_th)
        #2.发送请求,获取响应
        parse_th = threading.Thread(target=self.parse_url) 
        thread_list.append(parse_th)
        #3.提取数据
        content_th = threading.Thread(target=self.get_content)  
        thread_list.append(content_th)
        #4.保存数据
        save_th = threading.Thread(target=self.save_file)
        thread_list.append(save_th)
        # 启动线程
        for t in thread_list:
            t.setDaemon(True) #把子线程设置为守护线程,该线程不重要主线程结束,子线程结束
            t.start()

        for q in [self.url_queue,self.html_queue ,self.content_queue]:
        	q.join()          #让 主线程等待阻塞,等待队列的任务完成之后再完成
        
        
        

xiubai = XiuBai()
xiubai.run()
        
    




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值