驭虫术-Python(不定时更新)


title: Python驭虫术
tags: Python,爬虫,小书匠
grammar_cjkRuby: true
---
配图正在路上。

概念、工具 以及 协议

1.爬虫

  • 爬虫就是 模拟浏览器发送网络请求,获取响应,按照规则提取数据的程序
  • 爬虫要的就是保存数据,只抓取不保存毫无用处

    2.数据流向

  • 呈现出来,用于网页服务,或应用服务
  • 进行保存、数据分析

3.需要的软件与环境

  • 至少要有python环境
  • Pycharm或者其他IDE
  • chrome浏览:分析网页源码

4.浏览器的请求

  • url:可以进行解码或转码
  • 谷歌(浏览器)中的请求内容>Network
  • 爬虫和浏览器请求的URL地址有一定差别。elements与Network中的源码会不一样。

5.HTTP与HTTPS

  • Http:超文本传输协议:以明文方式进行传输,效率更高
  • Https:Http+SSL(安全套接字层):传输数据之前,将数据加密,之后解密,效率较低,但是更安全
  • HTTP协议:
    • 请求:
    1. 请求行
    2. 请求头:
      • Status code:状态码
      • Conection: keep-alive 支持长连接
      • Cache-Control:max-age=0 缓存控制为零
      • User-Agent:浏览器(内核)身份标识
      • Upgrade-Insecure-Requests:支持将不安全请求转换的功能
      • Accept:表示我想接收什么数据,q=权重
      • Cookie:浏览器保存在用户本地的一些信息,包括用户密码,账号信息,网站校验信息(例如csrf跨站保护)。会被携带发送给服务器。Cookie可以被服务器用来判断客户端是否是爬虫。
      • Query-String-Parameters:请求数据(GET)
      • From-data:请求数据(POST)
      • 可以在Chorme中模拟多种版本的机器
    3. 请求体
      • GET请求没有请求体,数据放在URL中
      • POST请求有请求体:携带数据,参数放置于请求体中,常用于登陆注册、传输大文本。
    • 响应:
    1. 响应头
      • set-Cookie:服务器给本地设置的cookie信息,服务器通过该字段设置cookie
    2. 响应体
      • URL地址对应的响应
    • 抓包:就是按一下F12,看一下浏览器发送了什么请求的信息,这个过程就叫做抓包

requests模块

  • requests模块是一个第三方包:用于处理数据请求,模拟http请求。
  • http请求的get请求方式

    url = "http://www.baidu.com/"
    response = requests.get(url=url)

  • http请求的post请求方式

    url = "http://www.baidu.com/"
    data = {键:"值"}
    response = requests.get(url=url,data=data)
  • 伪造(重塑)头部信息:

    headers={"键":"值,}
    response = requests.get(url=url,headers=headers)

    超时参数

  • 配合异常捕获,在指定时间返回响应

    # 在三秒内必须返回响应,否则则会报错
    response = requests.get(url=url,headers=headers,timeout=3)

    response方法:

  • response.text:获取源代码(易出现乱码)
    • response.encoding = response.apparent_encoding:设置服务器的编码为本地的编码
  • response.content.decode():把相应的二进制流,转化成str类型

    # 这里的gbk 是 可选参数
    response.content.decode("gbk")
  • response.request.url :请求的目标url地址
  • response.url :响应的url地址,这个有时候会因为跳转而和请求目标地址不一致
  • response.request.headers 请求头
  • response.headers 响应头

  • requests方式比urlib方式简单
  • 50%的动态内容:json格式的数据。

retring模块:

  • 第三方模块,用于重试异常
  • 用于重试出现异常的函数:通俗理解是,“出事了我都这,你尽管去做,做错了也不怕,但最多三次”

    from retrying import retry
    # 作为装饰器 装饰函数,报错仍然重复执行,直到三次才算出错
    @ retry(stop_max_attempt_number=3)
    def fun1():
    print("hello world.")
    time.sleep(1)
    raise ValueError("This is a test error.")

处理cookie相关的请求

  • DEMO:人人网
  • 直接携带cookie,然后请求URL
    • 直接放在headers中
    headers = {"Referver":"URL","User-Agent":"浏览器信息","Cookie":"..."}
    • cookie字典传给cookie参数,这个办法非常酷。Cookie参数只接收字典。【传说中的字典推导式】
    # Cookie字符串
    CookieStr = "anonymid=jm5lz4q0wv29sz; depovince=BJ; _r01_=1; JSESSIONID=abcpoYHrUXJZa6yQOiLxw; ick_login=4c5c0781-d37e-44c5-98a7-8e3fee81d222; ick=e74b83d4-c258-4de9-bd6c-3426f777fadd; XNESSESSIONID=949847ff1bf9; jebe_key=38dc9339-f175-472f-9288-02e4e7e4b59c%7Cd931901a60720bfd1a4f2f38c98639f3%7C1537147847212%7C1%7C1537147849534; wp_fold=0; jebecookies=054ec649-ffed-4989-beda-1be907785a33|||||; _de=BA25AEE63DF6B7A91E89E9A775AD2FBD; p=5929761e2707b622b09b23f92b3c04aa8; first_login_flag=1; ln_uact=15661592012; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; t=aaf1d9103cf916e1d824260c832ceaf38; societyguester=aaf1d9103cf916e1d824260c832ceaf38; id=968054908; xnsid=1acd462c; ver=7.0; loginfrom=null"
    # 这是一个字典生成式,生成正式使用的Cookie
    Cookie = {i.split("=")[0]:i.split("=")[1] for i in CookieStr.split(";")}
    response = requests.get(url=url,headers=headers,cookies=Cookie)
  • 通过session模块获取cookie:(这应是最常用的方法)
    1. session = requests.session() 会话保持,实例session
    2. session.post(post_url,data,headers) 很多网页的接口可以在表单的action提交地址中看到,但有一些需要抓包才能看到
    3. response = session.get(url,headers)
    • 使用session不仅可以处理相关登陆,而且可以应对相关反爬措施。
  • 处理登陆相关的验证码可以找:打码兔

数据提取方法

JSON

  • 数据交换格式,在Python的识别中其实是一个字符串
  • 学习处理和操纵json数据,非常重要
  • 导入标准库模块jsonimport json
  • json.loads(JSON数据) Json字符串重载为Python可识别的字典(dict)类型
    • 将Json字符串转化为Python容器类型(Dic,List)
    Py_data = json.loads(response.text)`
  • json.dumps(dict) 字典转换成json字符串
    • 把Python数据格式转化成字符串
    Js_data = json.dumps(Py_data)
    • dumps参数;ensure_ascii=False 取消ASC编码
    Js_data = json.dumps(Py_data,ensure_ascii=False)
    • dumps参数;indent=2 以首行缩进两个空格 的形式打印或保存,美化效果
    Js_data = json.dumps(Py_data,indent=2)
  • 浏览器的手机模式
  • 抓包:
    • 过滤:可以通过过滤URL来大幅提高抓包效率
    • Preview:中文不会被编码,会直接正常显示
  • API的获取注意:动态数据无法正常显示,很可能是Referer导致的

Xpath与lxml

Xpath是一种提取数据的语言

  • 当使用Xpath-helper工具 定位到任何一个节点,该节点都会得到一个名为xh-highlight的class属性做标识
  • XPath-helper插件
  • 解析网页内容:静态内容(源代码中有的)。
  • ctrl+shift+x 呼出XPath-helper
  • 按住shift移动光标,快速捕获响应的xpath
  • 1.选择节点对象(标签)
    • /html/head/meta:能够选中html下的head下的所有的meta标签
  • 2.从任意节点开始选择
    • //li:当前页面所有的li标签
    • /html/head/link//li:表示meta下的所有li标签
  • 3.定位到具体元素 [@]
    • //div[@class="father"]//li: 获取class名为father的div下的所有li标签
    • 可以使用单引号
    • 在页面中,定位id往往比定位class更合适
  • 4.获取节点内文本 text()
    • //a/text():获取a标签中直接裸露的文本内容
    • a//text():获取a下的所有文本,包括子节点文本
  • 5.选择节点属性内容
    • a/@href:获取a标签中 href属性中的内容

      xpath方法

  • string()函数 提取多个子节点中的文本
# 获取词语解释
w_ex = html2.xpath('//*[@id="content"]/div[2]')[0].xpath("string(.)")

lxml模块

  • 第三方模块,解析xml内容
  • etree.HTML方法,将响应的代码格式化,解析成标准的html格式。
  • @后面跟属性,如果放在方括号中,代表对所过滤的标签集合进行过滤。如果放在url后,则代表获取该属性的值

    etree.HTML(response.text)

相对路径与绝对路径

  • /是绝对路径,绝对路径的查找难度比较大,比较麻烦
  • //是相对路径,一般情况下我们都使用相对路径进行查找

mango数据库或文件夹

  • 保存爬取内容
  • 在xpath中的下标切片,不支持负索引,而且是从一开始,而不是从零开始的。
  • 把tbody去掉就好用了

JSON-View插件

  • 更便于查看JSON数据,在原来的基础上,优化了JSON数据的显示格式

response

  • text方法,响应的源代码,字符串类型;可以提取汉字。
  • encoding编码

    # 将响应信息编码改为网站制定编码
    response.encoding = response.apparent_encoding

文件操作

  • os模块,用于操作系统文件
  • 判断文件夹是否存在

    dir = "directory"
    if not os.path.exsits(dir):
    pass
  • 创建文件夹

    dir = "directory"
    os.mkdir(dir)

  • 打开文件与文件读写

    with("file_name","w+",encoding="utf-8") as f:
    f.write(content)

爬取动态内容与基础反爬

  • 网页是响应式加载,而不是一次性全部自动加载的
  • Grome浏览器F12:
    • Network中可以查看请求信息
    • Network-XHR 查看动态请求信息
  • user-agent/eɪdʒənt/:显示请求浏览器的内核

    # 获取返回响应信息头部,这个不是很重要
    for v,j in response.headers.items():
    print(v,':',j)
    # 获取请求信息头部
    for v,j response.request.headers.items():
    print(v,':',j)
  • 伪造请求信息浏览器内核

    headers = {
    'User-Agent':'伪造的浏览器内核信息'
    }
    response = requests.get(url=url,headers=headers)
  • Referer溯源伪造
    有些网址的反爬策略是:某些网址的特定网页会识别客户端的refer信息,这些信息包含了客户端的请求记录。它的具体意思是,你必须经由访问了我的主页,跳转到我的子页面,而不是从URL直接过来。你先开我家门,才能到我的卧室,而不是从窗户进来。否则就认为你是不合法的。

    headers = {
    'Referer':'伪造的 上一级URL'
    }
    response = requests.get(url=url,headers=headers)
  • 在XHR中可以找到动态数据,以及动态数据的请求接口。
  • 将json数据格式,格式化

    py_date = json.loads(response.text())

IP代理 requests.proxies

  • 相关则是随机数模块 random

    # 代理IP列表
    proxies = [{"http":“133.12.45.12:8564”},{"协议":"IP:端口号"}]
    # random随机选择列表中的一个元素生成代理
    proxy = random。choice(proxies)
    response = requests.get(proxies=proxy)

MongoDB 数据库

  • 基于分布式数据库,非关系性数据库中最接近关系型数据库。
  • 库→集合→文档
  • 服务器端开启服务

    mongod.exe --dbpath C:\data\db(路径)
    指定服务地址
  • 开启客户端

    mongod(在环境变量下)
  • 创建数据库

    use DB_NAME
  • 插入数据(创建集合)

    db.tb_name.insert({key:value})
  • 查看数据库

    show dbs;
  • 删除数据库

    db.dropDatabase()
  • 创建集合

    db.createCollection("set_name")
  • 查看集合

    show collections
  • 删除集合

    db.collection.drop()

    建立代理

  • 建立代理

    proxies = [{"http":"113.122.8.45:53128"},{"http":"114.122.8.45:53128"},{"http":"115.122.8.45:53128"}]
  • 导入随机数模块

    proxy = random.choice(proxies)

Retrying 模块

  • pip install retrying (安装)
  • timeout=5 超时参数

Scrapy框架

  • 建立爬虫的命令方式
    scrapy genspider x www.x.com
    `# 这里使用的版本是1.0以上的版本,在填写爬虫域名的时候 不需要加引号
  • 运行爬虫
    scrapy crawl x
  • 扩展:
    • 查看爬虫项目的模式列表
    >>>scrapy genspider -l 
    Available templates:
    basic
    crawl
    csvfeed
    xmlfeed
    • 使用上述模式中的一种,指定它,使用它进行开发(构建)爬虫文件。

spider.py文件:

爬虫文件是整个框架中我们最常编写的,里面包括一些内容需要我们学习。

extract()函数

  • 代替etree将格式化后的源码内容输出

parse()函数

  • parse() 是spider的一个方法。
  • 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。
  • 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

setting.py文件:

这里的配置有很多,但并不是我们所学的全部,譬如分布式设定,是要自己手写进去的

  • robots.txt的规则遵循设定:这里设置是否遵循robots文件的协定,一般情况下设置成False就行
# Obey robots.txt rules
ROBOTSTXT_OBEY = False      # default:True
  • 设置全局Header头:在settings.py文件中搜索就可以找到,取消注释之后可以将headers头信息加入进去。(在DownloadMiddlewares【下载中间件】中也可以加headers请求头信息,cookie,代理等。)
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
#}
  • 设置爬取间隔:在制定范围内随机的秒数作为爬取间隔,下面这个五表示的是最大爬取间隔时间(框架会从中1~5秒中选取一个时间点),并不是每次爬取都使用这个数字作为间隔秒数。

# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
  • 开启入库入口文件piplines.py的使用:在setting.py中可以找到这些代码,将它解开,就可以使用。同时还可以在ITEM_PIPELINES字典中设置新的内容(这些内容就是piplines.py中新的类),并且给它设置不同的优先级。指数越低,优先级越高。
#ITEM_PIPELINES = {
#    'Csdnboke.pipelines.CsdnbokePipeline': 300,
#}

piplines.py文件:

一种去重方法

  • 首先建立一个新的,使用逻辑实现去重,源代码如下:
# 导入模块
from scrapy.exceptions import DropItem
# 建立一个用于去重的类
class Set_it(object):
    # 建立一个构造方法
    def __init__(self):
        self.set0 = set()
    # 建立一个process_item方法,它会自动调用
    def process_item(self, item, spider):
        # 标题
        title = item["title"]
        # 判断标题是否已经存入了set中
        if title in self.set0:
            # 将这条item记录删除,并且输出一条提示信息
            raise DropItem("这一条内容已经存在了,所以我把它删了:%s"%title)
        # 否则将标题存入
        else:
            # 
            self.set0.add(title)
        return item

newspaper(第三方爬虫包)

newspaper是一个第三方包,用于快速抓取页面信息。它的开发团队来自于美国,现在还仍在维护当中。如果要使用,首先要保证在你的电脑上下载并安装这个包,对此,我们可以使用pip这样的包管理器进行直接下载安装,当然,用conda也可以。

  • 安装newspaper
pip install newspaper3k
  • 在Python爬虫文件中导入它
import newspaper
  • 使用实例化一个newspaper的Article方法,这个方法接收两个参数,第一个参数是Url,第二个参数是区域语言。
# 实例化Article
# demo:
# news = newspaper.Article()
news = newspaper.Article(url=base_url,language='zh')
  • 执行Article的download方法保存源码,然后执行parse方法,这两步是目前必须的
news.download()
news.parse()
  • 获取页面正文
content = news.text
  • 获取页面标题
title = news.title
  • 获取文章内配图
img = news.imges

【源代码】我自己开发了一个转字典为sql语句的脚本

#coding=utf-8
'''非常厉害的包 v1.0
使用说明:首先要保证你的items中的键值与数据库中的字段吻合,其次要自己建立库和数据表,
传入你的item,并且传入表的名称
form:Asterism
'''
def sql(item,table):
    '''
    item: Your dict.
    table: Your table name.
    '''
    # 生成两个列表推导式
    keylis = [key for key,values in item.items()]
    vlis = [values for key,values in item.items()]
    # 生成sql 语句中所需要的
    str1215 = '"{}"'+',"{}"'*(len(item)-1)
    str1217 = '{}'+',{}'*(len(item)-1)
    str1216 = 'insert into '+table+'('+str1217+')'+' value ('+str1215+')'
    _sql = str1216.format(*keylis,*vlis)
    return _sql      # 返回sql语句

猜你喜欢

转载自www.cnblogs.com/Asterism-2012/p/10061112.html