【Python】requests、bs爬虫



2018年05月03日    Author:Guofei

文章归类: 0xb0_Python语法    文章编号: 1252

版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2018/05/03/crawler.html


基础知识

URL的一般格式为(带方括号[]的为可选项):

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

URL由三部分组成:

  • protocol 是协议:http,https,ftp,file,ed2k…
  • hostname[:port]是存放资源的服务器的域名系统或IP地址(有时候要包含端口号,各种传输协议都有默认的端口号,如http的默认端口为80)。
  • 第三部分是资源的具体地址,如目录或文件名等。

爬虫步骤

  • 第一步获取网页 requests.get()
  • 第二步解析网页 BeautifulSoup
  • 第三步提取内容find_all/CSS selector
  • 第四步保存数据 txt,DB

requests

Keep-Alive & 连接池
国际化域名和 URL
带持久 Cookie 的会话
浏览器式的 SSL 认证
自动内容解码
基本/摘要式的身份认证
优雅的 key/value Cookie
自动解压
Unicode 响应体
HTTP(S) 代理支持
文件分块上传
流下载
连接超时
分块请求
支持 .netrc

快速上手

import requests

# get
r = requests.get('https://github.com/timeline.json')
# 定制url(见于下面get部分的章节)
# 定制请求头(见于下面get部分的章节)


# POST
s = requests.Session()
s.post(LOGIN_URL, data=payload, headers=dict(referer=LOGIN_URL))


# 响应内容
r.text # 文本内容,<str>
r.content # 二进制内容,<bytes>
r.json # json
r.raw # 原始内容

# 其它
r.status_code # 响应状态,200表示正常,404表示404
r.url #url
r.request # 发起请求的方式,get或其它
r.headers #头,是一个字典
r.encoding # 网页的编码方式

get

定制url

r = requests.get('http://www.guofei.site/',{'value1':'key1','value2':'key2'})
#r.url是'http://www.guofei.site/?value1=key1&value2=key2'

定制headers

# 方法1:get时定义header
headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
}
r = requests.get(url, headers=headers)


# 方法2:get后定义header
r.headers.update(headers)

post

payload={'value1':'key1','value2':'key2'}
r=request.post(url,data=payload)

高级方法

伪装身份发送请求

  1. Headers
  2. Proxy代理
    requests.get(url,proxies=proxies)
    

Session和Cookie

Session对象能够跨请求保持某些参数。也会在同一个Session 实例发出的所有请求之间保持cookie。所以如果向同一主机发送多个请求,底层的TCP 连接将会被重用,从而带来显著的性能提升。

s=request.Session()
result=s.get(url)
result.cookies

身份认证

许多要求身份认证的web服务都接受HTTP Basic Auth。这是最简单的一种身份认证,并且Requests 对这种认证方式的支持是直接开箱即可用。对于更加复杂的要求身份认证的网站无效,这种需要更厉害的技术。

超时

连接超时,读取超时

# 如果你指定单一值作为timeout,这一timeout 值将会用作connect 和read 二者的timeout。如下所示:
r = requests.get('https://github.com', timeout=5)
# 如果要分别指定,就传入一个tuple:
r = requests.get('https://github.com', timeout=(3.05, 27))
# 如果远端服务器很慢,你可以让Request 永远等待,传入一个None 作为timeout 值。
r = requests.get('https://github.com', timeout=None)

错误和异常

请求和就收的过程总不是一帆风顺的,这里也有你意想不到的“惊喜”

案例

用有道进行翻译

题目:写一个脚本,调用有道翻译网页版进行翻译 http://fanyi.youdao.com/

  1. 点开网页,审查元素,点击 network
  2. 刷新网页、或者重新点一次按钮、或者不操作
  3. 看每一个 Name 对应的 Preview ,找到需要的元素
  4. 找到所需元素后,点击 Preview 旁边的 Headers ,查阅关键信息
    • General
      • Request URL post实际发送到的地址
      • Status Code
    • Request Headers 很重要,里面存着网站用来反爬虫的信息。
      • User-Agent里面存着浏览器信息
    • Form Data 里面存着刚才提交的内容

下载一个文件

import requests

url = 'https://www.guofei.site/public/about/me.png'

resp = requests.get(url)

with open('me.png','wb') as f:
    f.write(resp.content)

BeautifulSoup

from bs4 import BeautifulSoup
import requests
r = requests.get('http://www.guofei.site/2018/04/19/statisticaltimeseries.html')
soup=BeautifulSoup(r.text,'lxml')
  • ‘html.parser’
  • ‘xml’:需要安装C语言库
  • ‘lxml’:需要安装C语言库
  • ‘html5lib’

BeautifulSoup 会把HTML文档转换成一个树形结构,每个节点都是一个Python对象 所有对象有4种

  • Tag(HTML标签)
  • NavigableString(标签的内容)
  • BeautifulSoup(文档的全部内容)
  • Comment(标签注释,特殊类型的NavigableString对象)

soup

print(soup.prettify()) # 用来看内容
soup.head # 返回Tag类型,内容是html的head
soup.p #返回Tag类型,内容是第一个 <p></p>的内容
soup.h2 #返回Tag类型
soup.span #返回Tag类型

# Tag操作
soup.p.attrs['test']='test_str'#取值或赋值
# soup.p是类似如下的形式
# <p test="test_str">Author:Guofei</p>
soup.p.string #返回bs4.element.NavigableString,内容就是对应的文本内容,如果是多节,返回空
soup.p.strings #返回 generator object 其内容是每一段的文本
soup.p.text #返回的是内部全部文本

遍历文档树

 直接子节点-.contents  .children
soup.head.contents #是一个list
soup.head.children #是一个 list_iterator

 所有子孙节点-.descendants
soup.head.descendants # generator object


 节点内容-.string
 多个内容- .strings  .stripped_strings
 父节点-.parent
 全部父节点-.parents
 兄弟节点-.next_sibling .previous_sibling
 全部兄弟节点-.next_siblings .previous_siblings
 前后节点-.next_element .previous_element
 所有前后节点-.next_elements .previous_elements

搜索文档树

find系列方法:

soup.find_all(name=None, attrs={'class':'content'}, recursive=True,text=None, limit=None, **kwargs) # 返回list
# <name class='content'> 对应tag.name,tag.attrs
# recursive=False 只搜索直接子节点
# text 文本内容,必须取全才能匹配到
# limit最多查找次数
# name可以接受字符串。正则表达式(re.compile("^b")。列表['p','a']。函数,函数接受tag本身,返回True/False

# 返回值可以继续获取子元素
soup[0].findChildren(name='td')



soup.find() #区别是只会返回第一个找到的
find_parents();find_parent()
find_next_siblings();find_next_sibling()
find_previous_siblings();find_previous_sibling()
find_all_next();find_next()
find_all_previous();find_previous()

CSS selector:

tag.select(selector, _candidate_generator=None,
limit=None)
# 通过标签名、class、id、标签和class及id的组合、属性查找
# 获取属性值、导航

您的支持将鼓励我继续创作!