目录
  1. 1. 爬虫概念、工具和HTTP
    1. 1.1. 什么是爬虫
    2. 1.2. 爬虫的数据的应用
    3. 1.3. 需要的软件和环境
    4. 1.4. 浏览器的请求
    5. 1.5. 认识HTTP、HTTPS
  2. 2. requests 模块的学习
    1. 2.1. 使用前:安装
    2. 2.2. 发送get,post请求,获取响应
    3. 2.3. response的方法
    4. 2.4. 获取网页源码的正确打开方式
    5. 2.5. 发送带header的请求
    6. 2.6. 使用超时参数
    7. 2.7. retrying 模块的学习
    8. 2.8. 处理Cookie相关的请求
  3. 3. ⭐️数据提取方法
    1. 3.1. json格式介绍
      1. 3.1.1. Json语法介绍
        1. 3.1.1.1. json.loads
        2. 3.1.1.2. json.dumps
      2. 3.1.2. 案例:豆瓣获取美剧分类爬虫案例
    2. 3.2. Xpath 和 lxml
      1. 3.2.1. xpath语法
      2. 3.2.2. 爬虫实例:获取某瓣的标题,url,图片地址,评论数,评分等信息
      3. 3.2.3. 基础知识点的学习
  4. 4. 最终案例
    1. 4.0.1. 写爬虫的讨论
传智播客--六节爬虫课

爬虫概念、工具和HTTP

什么是爬虫

  • 爬虫就是模拟客户端(游览器)发送网络请求,获取相应,按照规则提取数据的程序。
  • 模拟哭护短(浏览器)发送网络请求:照着浏览器发送一模一样的请求,获取和浏览器一模一样的数据。

爬虫的数据的应用

  • 呈现出来:展示在网页上,或者是展示在app上
  • 进行分析:从数据中寻找一些规律

需要的软件和环境

  • python3

    • 黑马python基础班15天视频
      1. 基础语法(字符串,列表,字典,判断和循环)
      2. 函数(函数的创建和调用)
      3. 面向对象(如何创建一个类,如何使用这个类)
  • chrome

    • 分析网络请求用的

浏览器的请求

  • url

    • 在chrome中点击检查,点击network

    • url = 请求的协议(http)+ 网站的域名 + 资源的路径 + 参数(?开头&隔开)

      https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=2&ch=&tn=baiduhome_pg&bar=&wd=abc&rsv_spt=1&oq=abc&rsv_pq=be41b8270005d8a9&rsv_t=79a6Pj%2Fov9dhzgOmd4MC%2FuaI%2BtckdddCpnaH14PJp9ERMVwi8LnwKPeMNppcdVBCvW06&rqlang=cn&rsv_enter=0&rsv_dl=tb
  • 浏览器请求url地址

    • 当前url对应的响应+js+css+图片 ----> elements中的内容
  • 爬虫请求的url地址

    • 当前url对应的响应
  • elements 的内容和爬虫获取到的url地址的响应不同,爬虫中需要以当前url地址对应的响应为准确提取数据

  • 当前url地址对应的响应在哪儿?

    • 从network中找到当前的url地址,点击response
    • 在页面上右键显示网页源码

认识HTTP、HTTPS

  • HTTP:超文本传输协议

    • 以明文的形式传输
  • HTTPS:HTTP + SSL(安全套接字层)

    • 传输之前数据先加密,之后解密获取内容

    • 效率较低,但是安全

  • Get 请求 和 Post 请求的区别

    • get请求没有请求体,post有,get请求把数据放到url地址中

    • post请求常用登录注册

    • post请求携带的数据量比get请求大,多,常用于传输大文本的时候

  • HTTP协议之请求

    1. 请求行

    2. 请求头(Headers)

      • User-Agent:用户代理:对方服务器能够通过user-agent知道当前请求对方资源的是什么浏览器
      • Connnection:Keep-alive:告诉对方我支不支持长连接
      • Accept-Encoding:gzip:为了使传输更快,一般会对数据进行压缩
      • Accept:text/html;q=0.9,image/web;q=0.8:指定接收的数据类型,q应该概率。
      • Accept-language:zh-CN;zh:指定支持语言的优先级
      • Cookie:用来存储用户信息,每次请求都会被携带上发送给对方的浏览器。
        • 要获取登录后才能访问的页面
        • 对方的服务器会通过cookie来判断我们一个爬虫
    3. 请求体

      • 携带数据
      • get请求没有请求体
      • post请求有请求体
  • HTTP协议之响应

    • 响应头
      • 大部分不用注意,只有一个属性set cookie
      • Set-Cookie:对方服务器通过该字段设置cookie到本地
      • 直接F12 response旁边就是cookie关注两个属性,字典:Name-Value
    • 响应体

requests 模块的学习

使用前:安装

  • pip install requests

发送get,post请求,获取响应

  • response = requests.get(url)#发送get请求,请求url地址对应的响应

    import requests
    url = "http://www.baidu.com"
    response = requests.get(url)
    print(response) # 返回的是状态码
  • response = requests.post(url,data={请求字典})#需要多传入一个请求体

    import requests 


    url="http://fanyi.baidu.com/basetrans"
    query_string={"query""人生苦短,我用python"
    "from""zh"
    "tol""en"}
    response = requests.post(url,data=query_string)
    print(response)

response的方法

  • response.text
    • 该方式往往会出现乱码
    • 所以在生成text之前需要先编码一下:response.encoding="utf-8"
  • response.content
    • print(response.content())输出的是b"str"二进制文件
    • 把相应的二进制字节流转换为str类型response.content.decode()
  • 属性
    1. response.request.url # 发送请求的url地址
    2. response.url # response相应的url地址
    3. response.requests.headers # 请求头
    4. response.headers # 相应请求

获取网页源码的正确打开方式

通过下面三种方式一定能够获取到网页的正确解码之后的字符串)

  1. response.content.decode(默认按照utf-8解码)
  2. response.content.decode("gbk")
  3. respnse.text浏览器以猜的方式解码,比较准确

发送带header的请求

即,request headers 请求头中的键值对:为了模拟浏览器,获取和浏览器一模一样的内容。

headers={
"User-Agent":"Mozilla/5.0(iPhone; CPU iPhone 0S 10_3 like Mac0S X)ApplewebKit/602.1.50(KHTML, like Gecko)Cri0S/56.0.2924.75 Mobile/14E5239e Safari/602.1",
"Referer":"http://fanyi. baidu. com/? aldtype=160471"
}

将头信息传入requests模块中:

response = requests.post(url,data=query,headers = headers)

使用超时参数

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

retrying 模块的学习

  • pip install retrying
  • 具体的使用
from retrying import retry 

@retry(stop_max_attempt_number =3 ) #让下面的模块反复执行三次
def _parse_url(url):
response = requests.get(url,headers=headers,timeout=5)
return response.content.decode()

def parse_url(url):
try:
html_str = _parse_url(url)
except:
html_str = None
return html_str

if __name__ = "__main__"
url = "https://www.baidu,com"
print(parse_url(url))

处理Cookie相关的请求

  • 人人网{“email":"mr_mao_hacker@163.com”,“password”:“alarmchime”}

  • 直接携带cookie请求url地址

    1. cookie 直接放在headers中,传入request

      headers = {"user-agent": "","Cookie":""}
    2. requests 语法内单独设置了cookies 传入位置【字典格式】

      # 正常cookie
      cookie = “”
      cookie_dict = {i.split("=")[0]:i.split("=")[1]for i in cookie.split(";")}

      response = requests.get(url,headers = headers,cookies = cookie_dict)
  • 先发送post请求,获取cookie,带上cookie请求登录后的页面

    1. session = requests.session() # session具有的方法和requests一样
    2. session.post(url,data,headers) #服务器设置在本地的cookie会被存在session
    3. session.get(url)#会带上之前保存在session中的cookie,能够成功
    import requests

    session = requests.session()

    # 使用session 发送post请求,获取对方保存在本地的cookie
    post_url = "https://www.wuxiaworld.com/account/login"
    headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"}
    post_data = {"Email": "2409277719@qq.com",
    "Password": "Wangjiahao526",
    "__RequestVerificationToken":" CfDJ8EwF1hLhM7pChLwkXvZCy55dmm-LnHaweNXreDzH7f9Q3nKbP1PtMCURW_HUeR3CjYSk4tRFYDmihxf89hMNpB9nQbGZgnGve_MMrM6iLfE348bxJv1iFcx_KL4se8y-GnBq-y_KiP6-42Ai2UQ_8U0",
    "RememberMe":"false"}

    response = session.post(post_url,headers=headers,data=post_data)


    # 以上应该能登录成功,成功后登录之前登录不上的个人页面
    url = "https://www.wuxiaworld.com/profile/bookmarks"
    response = session.get(url,headers = headers)

    with open("wuxiaworld3.html","w") as f:
    f.write(response.content.decode())

    两种方法获取以上的信息

    1. 浏览器的element查找,如需要传入关键字"Password"密码

      <input type=“password” class=“form-control valid” placeholder=“Password” data-val=“true” data-val-required=“The Password field is required.” id=“Password” name=“Password” aria-describedby=“Password-error” aria-invalid=“false”>

    2. 抓包,记住勾选 [ ]preserved log

      • 清空后,点击登录按钮,在Network中查找

⭐️数据提取方法

json格式介绍

  • 数据交换格式,看起来像python类型(列表,字典)的字符串

  • 使用json之前需要导入json库

  • 哪儿会返回json的数据

    • 浏览器切换到手机版
    • 抓包app

Json语法介绍

json.loads

  • 把json字符串转换为python类型
  • json.loads(json字符串)
  • 完整代码【百度翻译】

json.dumps

  • 把python类型转换为json字符串
  • json.dumps({"a":"a","b":2})
  • json.dumps(ret1,ensure_ascii=False,indent=2))
    • ensure_ascii:让中文显示成中文
    • indent:能够让下一行在上一行的基础上空格
    • 推荐使用这个函数,可以控制写入文件的一些参数

案例:豆瓣获取美剧分类爬虫案例

手机版可以返回Json格式

  • 如何找内容,同时在Resonse和Preview中查找黑镜

  • 遇到问题:缺少refer信息,导致的url地址无法访问。

    import requests
    url = ""
    headers = {
    "User-Agent":""
    "Referer":""}
    response = requests.get(url,headers= headers)
    print(response.content.decode())

    json_str = response.content.decode()

    ret1 = json.loads(json_str)#转换为python类型
    print(ret1)

    with open("douban.txt","w",encoding="utf-8") as f:
    f.write(json.dumps(ret1,ensure_ascii=False,indent=2))# indent 能达到换行空两格的效果,因为直接write就是一行内容,ensure_ascii能够直接不以ASCII格式保存字符
    • 如果url中有callback,没有用可以直接删掉,否则响应不是一个Json格式会报错
  • 暂补内容

    • 实例化
    • def run
    • 查询具体url的变化趋势:每次加18以及有个Total值
    • 定义 class 可以整理思路

Xpath 和 lxml

  • xpath

    • 一门从html中提取数据的语言

xpath语法

  • xpath helper:帮助我们从elements中定位数据【爬虫爬不到这个内容】
  • 判断是否定位到相应的属性:多`xh-highlight``
  1. 选择节点(标签)

    html/head/meta:能够选中html下的head下的所有的meta标签

  2. //:能够从任意节点开始选择

    //li:当前页面上所有的li标签

    /html/head//link:head下的所有的link标签

  3. @符号的用法

  • 选择具体某个元素://div[@class='feed-infinite-wrapper']/ul/li
    • 选择class='feed-infinite-wrapper’的div下的ul下的li
  • 直接选择某个属性的值:a/@href选择a的href的值
  1. 获取文本

    • /a/text():a下的标签
    • a//text():a下的所有文本,可以选到span中的所有内容
  2. 当前

    • ./a当前节点下的a标签
  • lxml

    • 安装:pip install lxml

    • 使用:

      from lxml import etree
      element = etree.HTML(“html字符串”)
      element.xpath("")

爬虫实例:获取某瓣的标题,url,图片地址,评论数,评分等信息

import lxml import etree
import request


url = "http://movie/douban.com/chart"
headers = {"User-Agent":""}

response = requests.get(url,headers=headers)
html_str = response.content.decode()

print(html_str)

# 使用etree处理数据
html = etree.HTML(html_str)
print(html)# 这里得到的是一个element对象

# 这里写xpath必须按照网页源内容写,而不能按照element内容写(之前的做法是错误的)

#1.获取所有的电影的url地址
url_list = html.xpath("")
print(url_list)

#2.获取所有图片的地址
img_list = html.xpath("")

#3.需要把每部电影组成一个字典,字典中是电影的各种数据,比如标题,url,图片地址,评论数,评分
# 思路:
#1.分组
#2.每一组提取数据

ret1 = html.xpath("")#取出的实际上是element,我们依然可以使用xpath
print(ret1)

for table in ret1:
item = {}
item["title"] = table.xpath("")
item["href"] = table.xpath("")
item["img"] = table.xpath("")
item["comment_num"] = table.xpath("./")
item["rating_num"] = table.xpath("./")
print(item)

基础知识点的学习

  • format:字符串格式化的一种方式

    "传智{}播客".format(1)
    "传智{}播客".format([1,2,3])
    "传智{}播客".format({1,2,3})
    "传智{}播客{}".format({1,2,3},[1,2,3])
    "传智{}播客{}".format({1,2,3},1)
  • 列表推导式

    • 帮助我们快速的生成包含一堆数据的列表

      [i+10 for i in range(10)]–> [10,11,12,…,19]

      ["10月{}日".format(i) for i in range(1,10)]–>[“10月1日”,“10月2日”,“10月3日”]

  • 字典推导式

    • 帮助我们快速的生成包含一堆数据的字典

      {i+10:i for i in range(10)}

      {"a{}".format(i):10 for i in range(3)}
  • 三元运算符

    • if 后面的条件成立,就把if前面的结果赋值给a,否则把else喂给a
    a = 10 if 4>3 else 20 # a=10
    a = 10 if 4<3 else 20 # a=20

最终案例

from lxml import etree

class QiubaiSpider:

def __int__(self):
self.url_temp = "https://www.qiushibaike.com/8hr/page/{}/"
self.headers = {"User-Agent":""}

def get_url_list(self):#根据url地址的规律,构造url list
url = [self.url_temp.format{i} for i in range(1,14)]
return url_list

def parse_url(self,url):
print("now parseing :",url)
response = requests.get(url,headers=headers)
return response.content.decode()

def get_content_list(self,html_str):#3.提取数据
html = etree.HTML(html_str)
#1.分组
div_list = html.xpath("")
for div in div_list:
item = {}
item["author_name"] = div.xpath("./") if len(div.xpath("./"))>0 else None
item['content'] = div.xpath("./")
# 技巧:可以在element里面直接复制 xpath
item["img"] = "https:"+item["img"][0] if len(item["img"])>0 else None
content_list.append(item)
return content_list

def save_content_list(self,content_list):#保存
with open("qiubai.txt","a",encoding="utf-8") as f:
for content in content_list:
f.write(json.dumps(content,ensure_ascii=False))
f.write("\n")
print("保存成功")

def run(self):实现主要逻辑
#1.根据url地址的规律,构造url list(爬取豆瓣时,直接获取的方式得到地址)
url_list = self.get_url_list()
#2.发送请求,获取相应
for url in url_list:
html_str = self.parse_url(url)
#3.提取数据
content_list = self.get_content_list(html_str)
#4.保存(调用下方法即可)
self.save_content_list(content_list)


if __name__ == '__main__':
qiubai = QiubaiSpider()
qiubai.run
#对于列表不能直接strip(),可以用列表循环去 strip()

写爬虫的讨论

  1. url
    • 知道url地址的规律和总得页码数:构造url地址的列表【没有办法确定】
    • start_url:构造法
  2. 发送请求,获取响应
    • request
  3. 提取数据
    • 返回json字符串:json模块
    • 返回的是html字符串:lxml模块配和xpath提取数据
  4. 保存
文章作者: Jacky
文章链接: https://wangjs-jacky.github.io/2019/12/09/%E4%BC%A0%E4%BC%A0%E6%99%BA%E6%92%AD%E5%AE%A2_%E5%85%AD%E8%8A%82%E7%88%AC%E8%99%AB%E8%AF%BE/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Jacky's blogs