14-通用爬虫模块-数据获取

爬虫基本概念

1. HTTP和HTTPS
HTTP:超文本传输协议,默认端口80
HTTPS:HTTP+SSL(安全套接字层),默认端口443
HTTPS比HTTP安全,但性能低。

2. url形式
形式:scheme://host[:port]/path/.../[?query-string][#anchor]
scheme:协议(例如http、https、ftp)
host:服务器的ip地址或者域名
port:服务器端口号(如果是走协议默认端口,如80 or 443)
path:访问资源的路径
query-string:参数,发送给http服务器的数据
anchor:锚(跳转到网页的指定锚点位置)
http://localhost:4000/filepart1/1.html
http://item.jd.com/119876.html/#product-detail

3. url请求形式

url请求形式 .png

4. HTTP常见请求头

  • Host:主机和端口号
  • Connection:链接类型
  • Upgrade-Insecure-Requests:升级为https请求
  • User-Agent:浏览器名称
  • Referer:页面跳转处
  • Accept:传输文件类型
  • Accept-Encoding:文件编解码格式
  • Cookie
  • x-Rquested-with:XMLHttpRequest(是Ajax异步请求)

5. 响应状态码

  • 200:成功
  • 302:临时转移至新的url
  • 307:临时转移至新的url
  • 404:not found
  • 500:服务器内部错误

6. 爬虫的分类

  • 通用爬虫:通常指搜索引擎的爬虫
  • 聚焦爬虫:针对特定网站的爬虫


    爬虫流程.png

7. 爬虫的概念
网络爬虫(又被称为网络蜘蛛,网络机器人),就是模拟客户端发送网络请求,接收请求响应,一种按照一定的规则,自动的抓取互联网信息的程序。
只要浏览器能做的事情,理论上,爬虫都能做。

8. 爬虫的更多用途

  • 12306抢票
  • 网站上的投票
  • 短信轰炸

9. 通用搜索引擎的局限

  • 通用搜索引擎里返回的网页里90%的内容都无用
  • 图片、音频、视频多媒体的内容通用搜索引擎无能为力
  • 不同的用户搜索的目的不完全相同,但是返回内容相同

10. ROBOTS协议
Robots协议:网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。
https://www.taobao.com/robots.txt

11. 页面上的数据在哪里

  • 当前url地址对应的响应中
  • 其他的url地址对应的响应中
    • 比如ajax请求中
  • js生成的
    • 部分数据在响应中
    • 全部通过js生成
爬虫request库

1. requests使用入门
【文档地址】http://docs.python-requests.org/zh_CN/latest/index.html
requests和urlib的区别:

  • requests的底层实现就是urlib
  • requests在python2和python3中通用,方法完全一样
  • requests简单易用
  • requests能够自动帮助我们解压(gzip压缩等)网页内容

2. requests中解决编解码的方法

  • response.content.decode()
  • response.content.decode("gbk")
  • response.text

3. response.text和response.content的区别

  • response.text
    • 类型:str
    • 解码类型:根据HTTP头部对响应的编码作出有根据的推测,推测的文本编码
    • 如何修改编码方式:response.encoding="gbk"
  • response.content
    • 类型:bytes
    • 解码类型:没有指定
    • 如何修改编码方式:response.content.decode("utf8")

4. 保存图片

import requests

r = requests.get("https://www.baidu.com/img/bd_logo1.png")

with open("a.png", "wb") as f:
    f.write(r.content)

5. 发送简单的请求

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

response 的常用方法:

response.text
response.content
response.status_code
response.request.header
response.headers

6. 发送带header的请求

  • headers的形式:字典
  • headers= {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}
  • 用法:response = requests.get(url, headers = headers)

7. 发送带参数的请求

  • 例如:http://www.baidu.com?wd=python&c=b
  • 参数形式:字典
  • kw = {"wd":"长城"}
  • 用法:requests.get(url,params=kw}

8. 贴吧爬虫

import requests


class TiebaSpider:
    def __init__(self, tieba_name):
        self.tieba_name = tieba_name
        self.url_temp = "https://tieba.baidu.com/f?kw="+tieba_name+"&ie=utf-8&pn={}"
        self.headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}

    def get_url_list(self):  # 构造url列表
        # url_list = []
        # for i in range(1000):
        #     url_list.append(self.url_temp.format(i * 50))
        # return url_list
        return [self.url_temp.format(i*50) for i in range(1000)]

    def parse_url(self, url):  # 发送请求,获取响应
        response = requests.get(url, headers=self.headers)
        return response.content.decode()

    def save_html(self, html_str,page_num):  # 保存html字符串
        file_path = "{}-第{}页.html".format(self.tieba_name, page_num)
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(html_str)

    def run(self):  # 实现主要逻辑
        # 1. 构造url列表
        url_list = self.get_url_list()
        # 2. 遍历,发送请求,获取请求
        for url in url_list:
            html_str = self.parse_url(url)
            # 3. 保存
            page_num = url_list.index(url) + 1  # 页码数
            self.save_html(html_str, page_num)


if __name__ == '__main__':
    tieba_spider = TiebaSpider("李毅")
    tieba_spider.run()

9. 发送POST请求

  • 登录注册(post比get安全)
  • 需要传输大文本内容的时候(post请求对数据长度没有要求)
  • 用法:response = requests.post("http://www.baidu.com/",data=data,headers=headers)
  • data形式:字典

百度翻译爬虫

mport requests
import json
import sys

query_string = sys.argv[1]

headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"}

post_data = {
    "query": query_string,
    "from": "zh",
    "to": "en",
}

post_url = "http://fanyi.baodu.com/basetrans"

r = requests.post(post_url, data=post_data, headers=headers)

dict_rect = json.loads(r.content.decode())

ret = dict_rect["trans"][0]["dst"]

print("resulst is :", ret)

10. 使用代理

  • 让服务器以为不是同一个客户端在请求
  • 防止我们的真是地址被泄漏,防止被追究
代理.png
代理.png
  • 用法:request.get("http://www.baidu.com",proxies)
  • proxies:字典
proxies:{
      "http":"http://12.34.56.78:9527",
      "https":"https://12.34.56.78:9527"
}

11. 使用代理ip注意事项

  • 准备一堆ip地址,组成ip池,随机使用一个ip地址来使用

  • 如何随机选择代理ip

    • {"ip":ip,"times":0}
    • [{},{},{},{},...] 对这个ip池进行排序,按照使用次数排序
    • 选择使用次数较少的10ip,从中随机选择一个
  • 检测ip代理可用性

    • 使用request添加超时参数,判断ip地址的质量
    • 在线代理ip质量检测的网站

12. cookie和session区别

  • cookie存储在客户的浏览器上,session数据放在服务器上
  • cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗
  • session会在一定时间保存在服务器上,当访问增多,会比较占用服务器的性能
  • 单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie

13. 爬虫处理cookie和session

  • 带上cookie和session的好处:能够请求到登录之后的页面

  • 带上cookie和session的弊端:

    • 一套cookie和session往往和一个用户对应
    • 请求太快,请求次数过多,容易被服务器识别为爬虫

不要cookie的时候,尽量不要去使用cookie
但是为了获取登录之后的页面,我们必须发送带有cookie的请求

14. 处理cookie和session请求
requests提供了一个session的类,来实现客户端和服务端的会话保持。
使用方法:
1.实例化一个session对象
2.让session发送get或者post请求
session = requests.session()
response = session.get(url,headers)

15. 请求登录之后网站的思路

  • 实例化session
  • 先使用session发送请求,登录网站,把cookie保存在session中
  • 再使用session请求登录之后才能访问的网站,session能够自动的携带登录成功时保存在其中的cookie,进行请求

16. demo

方式1:实例化session,使用session发送post请求,在使用他获取登录后的页面

import requests

session = requests.session()
post_url = "http://192.168.0.223:8080/redmine/login"
post_data = {"username": "zyx", "password": "30********35"}
headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"}
# 使用session发送post请求,cookie保存在其中
session.post(post_url, data=post_data, headers=headers)
# 在使用session进行请求登录之后才能访问的地址
r = session.get("http://192.168.0.223:8080/redmine/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%21&v%5Bstatus_id%5D%5B%5D=3&f%5B%5D=assigned_to_id&op%5Bassigned_to_id%5D=%3D&v%5Bassigned_to_id%5D%5B%5D=me&f%5B%5D=created_on&op%5Bcreated_on%5D=%3E%3D&v%5Bcreated_on%5D%5B%5D=2019-03-01&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&c%5B%5D=parent&c%5B%5D=start_date&c%5B%5D=due_date&c%5B%5D=done_ratio&group_by=")

# 保存页面
with open("renren.html", "w", encoding="utf-8") as f:
    f.write(r.content.decode())

方式2:headers中添加cookie键,值为cookie字符串

import requests

headers = {
"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
    "Cookie": "_redmine_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJTFlMzNjNjdjNWUyOGNkNDY5MjM2M2VmYWE4NGM2MTk2BjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMUM4N3M1bEJLT204dTlQWFkxcUw2bmRBUy9aSXVNTUxPelNaQTU2TTlreHc9BjsARg%3D%3D--025ba44479499b96abfbfdd8bc77ead00d4f0a4c",
}

# 在使用requests进行请求登录之后才能访问的地址
r = requests.get("http://192.168.0.223:8080/redmine/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%21&v%5Bstatus_id%5D%5B%5D=3&f%5B%5D=assigned_to_id&op%5Bassigned_to_id%5D=%3D&v%5Bassigned_to_id%5D%5B%5D=me&f%5B%5D=created_on&op%5Bcreated_on%5D=%3E%3D&v%5Bcreated_on%5D%5B%5D=2019-03-01&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&c%5B%5D=parent&c%5B%5D=start_date&c%5B%5D=due_date&c%5B%5D=done_ratio&group_by=")

# 保存页面
with open("renren2.html", "w", encoding="utf-8") as f:
    f.write(r.content.decode())

方式3:在请求方法中添加cookies参数,接收字典形式的cookie。字典形式的cookie中的键是cookie的name对应的值,值是cookie的value对应的值。
字典推导式、列表推导式

import requests

headers = {
        "User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
    }
cookies = "_redmine_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJTFlMzNjNjdjNWUyOGNkNDY5MjM2M2VmYWE4NGM2MTk2BjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMUM4N3M1bEJLT204dTlQWFkxcUw2bmRBUy9aSXVNTUxPelNaQTU2TTlreHc9BjsARg%3D%3D--025ba44479499b96abfbfdd8bc77ead00d4f0a4c"
cookies = {i.split("=")[0]:i.split("=")[1] for i in cookies.split("; ")}
print(cookies)
# 在使用requests进行请求登录之后才能访问的地址
r = requests.get("http://192.168.0.223:8080/redmine/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%21&v%5Bstatus_id%5D%5B%5D=3&f%5B%5D=assigned_to_id&op%5Bassigned_to_id%5D=%3D&v%5Bassigned_to_id%5D%5B%5D=me&f%5B%5D=created_on&op%5Bcreated_on%5D=%3E%3D&v%5Bcreated_on%5D%5B%5D=2019-03-01&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&c%5B%5D=parent&c%5B%5D=start_date&c%5B%5D=due_date&c%5B%5D=done_ratio&group_by=",cookies=cookies)

# 保存页面
with open("renren3.html", "w", encoding="utf-8") as f:
    f.write(r.content.decode())

17. 不发送post请求,使用cookie获取登录后的页面

  • cookie过期时间很长的网站
  • 在cookie过期之前能够拿到所有的数据,比较麻烦
  • 配合其他程序一起使用,其他程序专门获取cookie,当前程序专门请求页面
chrome分析post和json
  1. 寻找登录的post地址
  • 在form表单中寻找action对应的url地址

    • post的数据是input标签中的name的值作为键,真正的用户名密码作为值的字典,post的url地址就是action对应的url地址
  • 抓包

    • 勾选preserve log按钮,防止页面跳转找不到url地址
    • 寻找post数据,确定参数
      • 参数不会变,直接用,比如密码不是动态加密的时候
      • 参数会变
        • 参数在当前的响应中
        • 通过js生成
  1. 定位想要的js
  • 选择会触发js事件的按钮,点击event listener,找到js的位置

  • 通过chrome中的search all file来搜索url中的关键字

  • 添加断点的方式来查看js的操作,通过python来进行同样的操作

  1. 安装第三方模块
  • pip install retrying
  • 下载安装包,解压,进入解压目录 python3 setup.py install
  • **.whl,安装方法, pip install **.whl
  1. requests小技巧
import requests

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

print(response.cookies)
# 把cookie对象转换为字典
dict = requests.utils.dict_from_cookiejar(response.cookies)
print(dict)

url = "http://tieba.baidu.com/f/index/forumpark?cn=%E9%A6%99%E6%B8%AF%E7%94%B5%E5%BD%B1&ci=0&pcn=%E7%94%B5%E5%BD%B1&pci=0&ct=1&rn=20&pn=1"
# 对地址进行编码
url = requests.utils.quote(url)
print("编码:", url)
# 对地址进行解码
url = requests.utils.unquote(url)
print("解码:", url)

# 请求SSL证书验证
response = requests.get("http://eolinker.guxiansheng.cn/#/index", verify=False)
print(response)

# 设置超时参数
response = requests.get(url, timeout=10)

# 配合状态码判断请求是否成功
assert response.status_code == 200
import requests
from retrying import retry


headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36"}


@retry(stop_max_attempt_number=3)
def _parse_url(url, method, data, proxies):
    print("*" * 20)
    if method == "POST":
        response = requests.post(url, data=data, headers=headers, proxies=proxies)
    else:
        response = requests.get(url, headers=headers, timeout=3, proxies=proxies)
    assert response.status_code == 200
    return response.content.decode()


def parse_url(url, method="GET", data=None, proxies={}):
    try:
        html_str = _parse_url(url, method, data, proxies)
    except:
        html_str = None

    return html_str


if __name__ == '__main__':
    url = "www.baidu.com"
    print(parse_url(url))

你可能感兴趣的:(14-通用爬虫模块-数据获取)