文章目录

  • python爬虫-----网络数据采集
  • 一、爬虫基础案例:图片下载器
  • 遇到的问题:
  • 二、网络数据采集
  • 2.网络数据采集之requests库(常用)
  • requests方法
  • response对象
  • 高级应用一: 添加 headers
  • 2.fake_useragent:
  • 高级应用二: 代理设置
  • 报错:
  • 项目案例一: 京东商品的爬取
  • 项目案例二: 百度/360搜索关键词提交
  • 常见问题:
  • 小练习


python爬虫-----网络数据采集

一、爬虫基础案例:图片下载器

网络爬虫抓取过程可以理解为模拟浏览器操作的过程,所以深入理解 HTTP 协议更有利于爬虫的学习,并且该部分是面试官非常喜欢问的部分,很重要,详情请见:

import os
import re

import requests
from colorama import Fore


def download_image(url, keyword):
    """
    下载图片
    :param url: 百度图片的网址
    :return: Bool
    """
    #  1. 向服务器发起HTTP请求
    response = requests.get(url)
    #  2. 获取服务器端的响应信息
    #  响应信息: status_code, text, url
    data = response.text
    #  3. 编写正则表达式,获取图片的网址
    # "ObjURL":"http:\/\/img2.imgtn.bdimg.com\/it\/u=3459137507,1368309920&fm=214&gp=0.jpg"
    # 获取到的: http:\/\/img2.imgtn.bdimg.com\/it\/u=3459137507,1368309920&fm=214&gp=0.jpg
    # 正则的语法: .代表除了\n之外的任意字符, *代表前一个字符出现0次或者无数次. ?非贪婪模式
    pattern = r'"ObjURL":"(.*?)"'
    # 4. 根据正则表达式寻找符合条件的图片网址.
    image_urls = re.findall(pattern, data)
    # 5. 下载猫的图片到本地
    index = 1
    for image_url in image_urls:
        # 转义字符: \n, \t, \ , \\,
        image_url = image_url.replace('\\', '')
        print(image_url)  # 'xxxx.jpg   xxxx.png'
        # response.text返回unicode的文本信息, response.text返回bytes类型的信息
        try:
            response = requests.get(image_url)
        except Exception as e:
            print(Fore.RED + "[-]下载失败: %s" % (image_url))
        else:
            old_image_filename = image_url.split('/')[-1]
            if old_image_filename:
                image_format = old_image_filename.split('.')[-1]
                # jpeg?imageview&thumbnail=550x0
                if '?' in image_format:
                    image_format = image_format.split('?')[0]
            else:
                image_format = 'jpg'

            # 生成图片的存储目录, keyword='cat', 'dog', 'python django'
            keyword = keyword.replace(' ', '_')
            print(keyword)
            if not os.path.exists(keyword):
                os.mkdir(keyword)
            image_filename = os.path.join(keyword, str(index) + '.' + image_format)

            with open(image_filename, 'wb') as f:
                f.write(response.content)
                print(Fore.BLUE + "[+] 保存图片%s.jpg成功" % (index))
                index += 1

if __name__ == '__main__':
    keyword = input("请输入批量下载图片的关键字: ")
    # url地址里面参数信息可以长可以短, 有的参数可以省略的。
    url = 'http://image.baidu.com/search/index?tn=baiduimage&word=' + keyword
    print(Fore.BLUE + '[+] 正在请求网址: %s' % (url))
    download_image(url, keyword)

Python对接crt采集 python采集信息_IP

遇到的问题:

1.问题:[-]下载失败: http://img1.imgtn.bdimg.com/it/u=2384096151,2805439088&fm=214&gp=0.jpg
原因:反斜杠不识别
解决:遍历image_urls时将这里的反斜杠替换成空即可 image_url = image_url.replace("\\", "") 理解:要把反斜杠替换为

二、网络数据采集

1.网络数据采集之urllib库

2.网络数据采集之requests库(常用)

requests官方网址: https://requests.readthedocs.io/en/master/

requests方法

Python对接crt采集 python采集信息_数据_02


我们自己写一个服务器来测试,就不会有反爬

from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():
    # 获取用户GET提交的数据信息
    print(request.args)
    return 'index: %s' % (request.args)


@app.route('/post/', methods=['POST'])
def post():
    # 获取用户POST提交的数据信息
    print(request.form)
    # return 'post info: %s' % (request.form)
    username = request.form.get('username')
    password = request.form.get('password')
    if username == 'admin' and password == 'westos123':
        return 'login success'
    else:
        return 'login failed'


if __name__ == '__main__':
    app.run()

request中的 get和post

from urllib.error import HTTPError

import requests


def get():
    # get方法可以获取页面数据,也可以提交非敏感数据
    # url = 'http://127.0.0.1:5000/'
    # url = 'http://127.0.0.1:5000/?username=fentiao&page=1&per_page=5'
    url = 'http://127.0.0.1:5000/'
    try:
        params = {
            'username': 'fentiao',
            'page': 1,
            'per_page': 5
        }
        response = requests.get(url, params=params)
        print(response.text, response.url)
        # print(response)
        # print(response.status_code)
        # print(response.text)
        # print(response.content)
        # print(response.encoding)
    except HTTPError as e:
        print("爬虫爬取%s失败: %s" % (url, e.reason))


def post():
    url = 'http://127.0.0.1:5000/post'
    try:
        data = {
            'username': 'admin',
            'password': 'westos12'
        }
        response = requests.post(url, data=data)
        print(response.text)
    except HTTPError as e:
        print("爬虫爬取%s失败: %s" % (url, e.reason))


if __name__ == '__main__':
    get()
    # post()

#get方法结果
index: ImmutableMultiDict([('username', 'fentiao'), ('page', '1'), ('per_page', '5')]) http://127.0.0.1:5000/?username=fentiao&page=1&per_page=5

#post方法结果
login failed

运行我们的服务器,在运行request代码

response对象

Response对象包含服务器返回的所有信息,也包含请求的Request信息。

Python对接crt采集 python采集信息_IP_03

高级应用一: 添加 headers

1.有些网站访问时必须带有浏览器等信息,如果不传入headers就会报错。

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'}
response = requests.get(url, headers=headers)
2.fake_useragent:

UserAgent是识别浏览器的一串字符串,相当于浏览器的身份证,在利用爬虫爬取网站数据时,频繁更换UserAgent可以避免触发相应的反爬机制fake-useragent对频繁更换UserAgent提供了很好的支持,可谓防反扒利器。

UserAgent实质上是从网络获取所有的用户代理, 再通过random随机选取一个用户代理。

user_agent = UserAgent().random

安装:

pip install fake_useragent

3.测试
自己写的服务器
启动服务器,运行代码模拟浏览器访问服务器

"""
FileName: FlaskApp
Date: 09 18
Author: lvah
Connect: 976131979@qq.com
Description:

"""

from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():
    # 获取用户GET提交的数据信息
    print(request.args)
    print("客户端请求的user_agent: ", request.user_agent)

    return 'index: %s' % (request.args)


@app.route('/post/', methods=['POST'])
def post():
    # 获取用户POST提交的数据信息
    print(request.form)
    # return 'post info: %s' % (request.form)
    username = request.form.get('username')
    password = request.form.get('password')
    if username == 'admin' and password == 'westos123':
        return 'login success'
    else:
        return 'login failed'


if __name__ == '__main__':
    app.run()

启动服务器,运行代码模拟浏览器访问服务器

import requests
from fake_useragent import  UserAgent

def add_headers():
    # headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'}
    # UserAgent实质上是从网络获取所有的用户代理, 再通过random随机选取一个用户代理。
    # https://fake-useragent.herokuapp.com/browsers/0.1.11
    ua = UserAgent()
    # 默认情况下, python爬虫的用户代理是python-requests/2.22.0。
    response = requests.get('http://127.0.0.1:5000', headers={'User-Agent': ua.random})
    print(response)


if __name__ == '__main__':
    add_headers()

#运行结果
<Response [200]>

#去服务器端查看结果
ImmutableMultiDict([])
客户端请求的user_agent:  Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36

高级应用二: 代理设置

在进行爬虫爬取时,有时候爬虫会被服务器给屏蔽掉,这时采用的方法主要有降低访问时间,通过代理IP访问。ip可以从网上抓取,或者某宝购买。

比较有名的一个免费的IP代理是:西刺IP代理 https://www.xicidaili.com/nn/

proxies = { "http": "http://127.0.0.1:9743", "https": "https://127.0.0.1:9743",} 
response = requests.get(url, proxies=proxies)

测试
服务器

from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():
    # 获取用户GET提交的数据信息
    print(request.args)

    print("客户端请求的user_agent: ", request.user_agent)
    # print("客户端请求的IP:", request.remote_addr)
    return 'index: %s' % (request.args, request.remote_addr)


@app.route('/post/', methods=['POST'])
def post():
    # 获取用户POST提交的数据信息
    print(request.form)
    # return 'post info: %s' % (request.form)
    username = request.form.get('username')
    password = request.form.get('password')
    if username == 'admin' and password == 'westos123':
        return 'login success'
    else:
        return 'login failed'


if __name__ == '__main__':
    app.run(debug=True)
import requests
from fake_useragent import UserAgent

ua = UserAgent()
proxies = {
    'http': 'http://222.95.144.65:3000',
    'https': 'https://182.92.220.212:8080'
}
response = requests.get('http://47.92.255.98:8000',
                        headers={'User-Agent': ua.random},
                        proxies=proxies
                        )

print(response)
# 这是因为服务器端会返回数据: get提交的数据和请求的客户端IP
# 如何判断是否成功? 返回的客户端IP刚好是代理IP, 代表成功。
print(response.text)
报错:

1.报错:requests.exceptions.ProxyError: HTTPConnectionPool(host=‘222.95.144.65’, port=3000): Max retries exceeded with url: http://47.92.255.98:8000/ (Caused by ProxyError(‘Cannot connect to proxy.’, NewConnectionError(’<urllib3.connection.HTTPConnection object at 0x000001F379E31B70>: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。’)))
原因:此IP访问次数超过限制
解决:去西刺IP重新复制新的ip和端口在测试

项目案例一: 京东商品的爬取

Python对接crt采集 python采集信息_服务器_04

from urllib.error import HTTPError

import requests
from colorama import Fore
from fake_useragent import UserAgent


def download_page(url, parmas=None):
    try:
        ua = UserAgent()
        headers = {'User-Agent': ua.random}
        response = requests.get(url, params=parmas, headers=headers)
    except  HTTPError as e:
        print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, e.reason))
        return None
    else:
        # content返回的是bytes类型
        return response.content


def download_file(content=b'', filename='jd.html'):
    """
    :param content: 要写入本地的html字符bytes类型
    :param filename: 写入本地的文件名
    :return:
    """
    with open(filename, 'wb') as f:
        f.write(content)
        print(Fore.GREEN + '[+]写入文件%s成功' % (filename))


if __name__ == '__main__':
    url = 'https://item.jd.com/100012015170.html'
    html = download_page(url)
    download_file(content=html)

#项目案例二: 百度/360搜索关键词提交

    # url = 'https://www.so.com/s'
    # params = {
    #     'q': 'python'
    # }
    # content = download_page(url, params)
    # download_file(content)

运行代码

目录生成一个jd.html文件

用浏览器打开

可以看到是本地的地址:

Python对接crt采集 python采集信息_IP_05

项目案例二: 百度/360搜索关键词提交

百度的关键词接口:https://www.baidu.com/baidu?wd=xxx&tn=monline_4_dg
360的关键词接口:http://www.so.com/s?q=keyword

1.需求分析,至少要实现两个功能:一是搜索图片,二是自动下载
2.分析网页 http://image.baidu.com/search/index?tn=baiduimage&word=cat (注意:其中可以删除不用的参数,不影响页面的加载) 源代码,配合F12
3.编写正则表达式或者其他解析器代码
4.存储数据到本地
5.正式编写python爬虫代码

页面的分析是十分重要的,不同需求对应不同的URL,不同URL的源码显然是不一样的,所以掌握如何分析页面是成功爬虫的第一步。该页面的源码分析如下图所示:

Python对接crt采集 python采集信息_服务器_06

import os
import re

import requests
from colorama import Fore


def download_image(url, keyword):
    """
    下载图片
    :param url: 百度图片的网址
    :return: Bool
    """
    #  1. 向服务器发起HTTP请求
    response = requests.get(url)
    #  2. 获取服务器端的响应信息
    #  响应信息: status_code, text, url
    data = response.text  # 获取页面源码
    #  3. 编写正则表达式,获取图片的网址
    # data = ...[{"ObjURL":"http:\/\/images.freeimages.com\/images\/large-previews\/3bc\/calico-cat-outside-1561133.jpg",....}]...
    # 需要获取到的是: http:\/\/images.freeimages.com\/images\/large-previews\/3bc\/calico-cat-outside-1561133.jpg
    # 正则的语法: .代表除了\n之外的任意字符, *代表前一个字符出现0次或者无数次. ?代表非贪婪模式
    pattern = r'"objURL":"(.*?)"'
    # 4. 根据正则表达式寻找符合条件的图片网址.
    image_urls = re.findall(pattern, data)
    # 5. 根据图片网址下载猫的图片到本地
    index = 1
    for image_url in image_urls:
        print(image_url)  # 'xxxx.jpg   xxxx.png'
        # response.text 返回 unicode 的文本信息, response.text 返回 bytes 类型的信息
        try:
            response = requests.get(image_url)  # 向每一个图片的url发起HTTP请求
        except Exception as e:
            print(Fore.RED + "[-] 下载失败: %s" % (image_url))
        else:
            old_image_filename = image_url.split('/')[-1]
            if old_image_filename:
            	# 获取图片的后缀
                image_format = old_image_filename.split('.')[-1]
                # 处理 url 为...jpeg?imageview&thumbnail=550x0 结尾(传参)的情况
                if '?' in image_format:
                    image_format = image_format.split('?')[0]
            else:
                image_format = 'jpg'
                
            # 生成图片的存储目录
            keyword = keyword.split(' ', '-')
            if not os.path.exists(keyword):
                os.mkdir(keyword)
            image_filename = os.path.join(keyword, str(index) + '.' + image_format)
			# 保存图片
            with open(image_filename, 'wb') as f:
                f.write(response.content)
                print(Fore.BLUE + "[+] 保存图片%s.jpg成功" % (index))
                index += 1


if __name__ == '__main__':
    keyword = input("请输入批量下载图片的关键字: ")
    url = 'http://image.baidu.com/search/index?tn=baiduimage&word=' + keyword
    print(Fore.BLUE + '[+] 正在请求网址: %s' % (url))
    download_image(url, keyword)

运行上面代码结果:

Python对接crt采集 python采集信息_数据_07

常见问题:

(1)为什么只有30张图片,百度出来的不止30张
百度图片是响应式的,不断下拉会不断加载新的图片,也就是说浏览器中的页面是经过JS处理数据后生成的结果,涉及Ajax爬虫内容在此不做详细说明。
(2)在搜索页面下点开的单个图片的 url 与程序中获取的 ObjURL 是不一致的
这可能是百度经过缓存处理的结果,每个图片本质上是“外网的”,非百度的,所以在程序中选择向真正存储图片的 url 发起 HTTP 请求。

小练习

需求分析:通过输入要搜索的关键字,获取页面并将页面保存到本地。
结果展示:输入apologize 后,将获取到的页面存入本地,打开本地的html
代码:

from urllib.error import HTTPError

import requests

from fake_useragent import UserAgent
from colorama import Fore
def down_loadPage(url,params):
    try:
        ua=UserAgent()
        headers={'User-Agent':ua.random}
        response=requests.get(url,headers=headers,params=params)
    except HTTPError as e:
        print(Fore.RED + '[-] 爬取网站%s失败: %s' % (url, e.reason))
        return None
    else:
        return response.content
def down_filename(content=b'',filename='hello.html'):# response.content是bytes类型
    with open(filename,'wb') as f :
        f.write(content)
        print(Fore.GREEN + '[+]写入文件%s成功' % (filename))
if __name__ == '__main__':
    params = input('请输入要查询的字符:')
    url='http://www.youdao.com/w/eng/' +params+ '/#keyfrom=dict2.index'
    content=down_loadPage(url,params) #获取网页内容
    down_filename(content) #将内容下载到本地

Python对接crt采集 python采集信息_Python对接crt采集_08