爬虫笔记

爬虫分类

  1. 通用网络爬虫(搜索引擎使用,遵守robots协议)

    robots协议:网站通过robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,通过网络爬虫需要遵守robots协议。

    实例:www.baidu.con/robots.txt

  2. 聚焦网络爬虫:自己写爬虫程序

爬虫数据步骤

  1. 确定需要爬取的URL地址
  2. 有请求模块向URL地址发出请求,并得到网站响应。
  3. 从响应中提取数据
    1. 所需数据,保存
    2. 页面中有其它需要跟进的URL地址,继续第二部请求,如此循环

爬虫模块

requests模块

  1. 常用方法

requests.get()

【1】作用
	向目标网站发起请求,并获取对象
	
【2】参数
	url:需要抓取url地址
	headers:请求头
	timeout:超时时间,超时会抛出异常

http://httpbin.org/get这是测试网站可以返回请求数据

响应参数

import requests

result = requests.get('https://www.jd.com/')

# content响应内容为bytes,decode('utf-8')然后用utf-8解码
result = requests.get('https://www.jd.com/').content.decode('utf-8')

# text响应字符串
result = result.text

# content响应内容为bytes,爬取图片、音频、文件、视频
result = result.content

# http响应码result.status_code
code = result.status_code
print(code)

urllib.parse模块

这个库作用:url地址中有中文的可以对URL地址解码

from urllib import parse
params = parse.urlencode({'wd':'赵丽颖','pn':'10'})
print(params)

输出**************
#多个参数中间&符号会自动加上
wd=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=10

快速生成拼接URL

import requests
from urllib import parse

url = 'www.baidu.com/s?{}'
for i in range(1,101):
    page = (i-1)*10
    params = parse.urlencode({'wd': '赵丽颖', 'pn': str(page)})
    page_url = url.format(params)
    print(page_url)
    
    
*********************部分输出***********************
www.baidu.com/s?wd=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=0
www.baidu.com/s?wd=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=10
www.baidu.com/s?wd=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=20
www.baidu.com/s?wd=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=30

unquote(string)解码

#将编码后的字符串转为普通的unicode字符串
import requests
from urllib import parse

params = '%E8%B5%B5%E4%B8%BD%E9%A2%96'
result = parse.unquote(params)

*********************部分输出***********************
赵丽颖

案例:输入明星名称、开始页数、结束页数,爬取HTML到本地

【1】查看所抓取的数据在响应内容中是否存在,应为现在有好多数据时动态加载出来
	右键--查看网页源代码--搜索关键字
    
【2】查找并分析URL规律

【3】发送请求并获取响应内容
import requests
from urllib import parse
import time
import random


class BaiduTieba():
    def __init__(self):
        # https://tieba.baidu.com/f?kw=%E8%B5%B5%E4%B8%BD%E9%A2%96&pn=100
        self.url = 'http://tieba.baidu.com/f{}'
        self.header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'}

    def get_html(self, url, header):
        result = requests.get(url, headers=self.header).content.decode('utf-8')
        return result

    def parse_html(self):
        # 数据解析处理
        pass

    def save_html(self, filename, html):
        with open(filename, 'w') as f:
            f.write(html)

    def run(self):
        name = input('请输入明星名称:')
        start_page = input("请输入开始页数:")
        end_page = input("请输入结束页数:")
        # 解析URL和请求
        for page in range(int(start_page), int(end_page) + 1):
            pn = (page - 1) * 50
            #解码有中文URL并拼接页数
            params = parse.urlencode({'kw': name, 'pn': str(pn)})
            url = self.url.format(params)
            html = self.get_html(url, self.header)
            filename = '{}第{}页.html'.format(name, page)
            with open(filename, 'w', encoding='utf-8')as f:
                f.write(html)
            # 请求速度太快,随机休眠1-3秒
            time.sleep(random.randint(1, 3))


if __name__ == '__main__':
    sider = BaiduTieba()
    sider.run()

正则表达式

re模块使用流程

# 方法一,这个是常用,re.S作用:让正则表达式. 能匹配\n
r_list = re.findall('正则表达式',html,re.S)

# 方法二
pattern = re.compile('正则表达式',html,re.S)

例子:
import re
r_list = re.findall('AB','ABCABCABCDEFG')
print(r_list)

*********************部分输出***********************
['AB', 'AB', 'AB']

思考:请写出匹配任意一个字符正则表达式

import re
r_list = re.findall('.',html,re.S)

贪婪匹配和非贪婪匹配

  • 贪婪匹配(默认)
    1、在整个表达式匹配成功的前提下,尽可能多的匹配 * + ?
    2、表示方式: .* .+ .?
    
  • 非贪婪匹配
    1、在整个表达式匹配成功的前提下,尽可能少的匹配 * + ?
    2、表示方式: .*? .+? .??
    
  • 案例

    把文字抓取出来,一个元素一段文字

    import re
    
    html = """
    <div><p>你动我一下试试,我屠你满门</p></div>
    <div><p>你动她一下试试,我屠尽全世界</p></div>
    """
    r_list = re.findall('<div><p>.*</p></div>', html, re.S)
    print(r_list)
    
    *********************部分输出***********************
    ['<div><p>你动我一下试试,我屠你满门</p></div>\n<div><p>你动她一下试试,我屠尽全世界</p></div>']
    
    # 把正则匹配模式改成,非贪婪模式
    import re
    html = """
    <div><p>你动我一下试试,我屠你满门</p></div>
    <div><p>你动她一下试试,我屠尽全世界</p></div>
    """
    r_list = re.findall('<div><p>.*?</p></div>', html, re.S)
    print(r_list)
    
    *********************部分输出***********************
    ['<div><p>你动我一下试试,我屠你满门</p></div>', '<div><p>你动她一下试试,我屠尽全世界</p></div>']
    
    # 匹配加了括号,变成正则表达式分组,只提取匹配内容出来
    import re
    html = """
    <div><p>你动我一下试试,我屠你满门</p></div>
    <div><p>你动她一下试试,我屠尽全世界</p></div>
    """
    r_list = re.findall('<div><p>(.*?)</p></div>', html, re.S)
    print(r_list)
    
    *********************部分输出***********************
    ['你动我一下试试,我屠你满门', '你动她一下试试,我屠尽全世界']
    

正则表达式分组

  • 作用
    在完整的模式中第一子模式,将每个园括号中子模式匹配出来的结果提取出来
    
  • 案例
    import re
    s = 'A B C D E F G'
    r_list = re.findall('\w+\s+\w+', s, re.S)
    print(r_list)
    *********************部分输出***********************
    [('A', 'B'), ('C', 'D'), ('E', 'F')]
    **************************************************
    
    
    r_list = re.findall('(\w+)\s+\w+', s, re.S)
    print(r_list)
    *********************部分输出***********************
    ['A', 'C', 'E']
    **************************************************
    
    r_list = re.findall('(\w+)\s+(\w+)', s, re.S)
    print(r_list)
    *********************部分输出***********************
    [('A', 'B'), ('C', 'D'), ('E', 'F')]
    **************************************************
    
  • 分组总结
    1、在网页中,想要什么内容,就加()
    2、先按整体正则匹配,然后在提取分组()内容
    3、如果有两个以上分组(),则结果中以元祖形式显示[(),(),()]
    
  • 案例
    #爬取猫眼电影top100数据(电影名称、主演、上映时间)
    import requests
    import re
    import time
    import random
    
    url = 'https://maoyan.com/board/4?offset={}'
    #headers要稍微全的,不然又可能会验证
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Host': 'maoyan.com',
        'Sec-Fetch-Dest': 'document',
        'Sec-Fetch-Mode': 'navigate',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-User': '?1',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
    }
    for page in range(10):
        url = 'https://maoyan.com/board/4?offset={}'
        offset = page * 10
        url = url.format(str(offset))
        result = requests.get(url, headers=headers).content.decode('utf-8')
        #删除内容要加.*?  抓取数据要加(.*?)
        re_list = re.findall('<dd>.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>', result,re.S)
        print(re_list)
        time.sleep(random.randint(1, 5))
    
posted on 2021-01-10 23:27  xiao小胡子  阅读(77)  评论(0)    收藏  举报