2.请求模块的使用

请求模块的使用

requests

安装
pip install requests
用途

用于模拟请求网页链接,从而获得数据。

相关文档

中文文档

基本用法
Response
import requests

r = requests.get('https://www.baidu.com/')
print(type(r.status_code), r.status_code)
print(type(r.headers), r.headers)
print(type(r.cookies), r.cookies)
print(type(r.url), r.url)
print(type(r.history), r.history)
  • response.cookies:网页的cookies
  • response.text:网页的文本内容
  • response.status_code:网页的状态码
  • response.history:请求历史
  • response.url:网页URL

运行结果:

<class 'int'> 200
...
<class 'str'> https://www.baidu.com/
<class 'list'> []

Status Code 常用来判断请求是否成功,Requests 还提供了一个内置的 Status Code 查询对象 requests.codes。

import requests

r = requests.get('http://www.jianshu.com')

exit() if not r.status_code == requests.codes.ok else print("请求成功")

返回码和相应的查询条件:

# Informational.
100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('already_reported',),
226: ('im_used',),

# Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('permanent_redirect',
      'resume_incomplete', 'resume',), # These 2 to be removed in 3.0

# Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
421: ('misdirected_request',),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
425: ('unordered_collection', 'unordered'),
426: ('upgrade_required', 'upgrade'),
428: ('precondition_required', 'precondition'),
429: ('too_many_requests', 'too_many'),
431: ('header_fields_too_large', 'fields_too_large'),
444: ('no_response', 'none'),
449: ('retry_with', 'retry'),
450: ('blocked_by_windows_parental_controls', 'parental_controls'),
451: ('unavailable_for_legal_reasons', 'legal_reasons'),
499: ('client_closed_request',),

# Server Error.
500: ('internal_server_error', 'server_error', '/o\\', '✗'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
511: ('network_authentication_required', 'network_auth', 'network_authentication')# Informational.
100: ('continue',),
101: ('switching_protocols',),
102: ('processing',),
103: ('checkpoint',),
122: ('uri_too_long', 'request_uri_too_long'),
200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'),
201: ('created',),
202: ('accepted',),
203: ('non_authoritative_info', 'non_authoritative_information'),
204: ('no_content',),
205: ('reset_content', 'reset'),
206: ('partial_content', 'partial'),
207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'),
208: ('already_reported',),
226: ('im_used',),

# Redirection.
300: ('multiple_choices',),
301: ('moved_permanently', 'moved', '\\o-'),
302: ('found',),
303: ('see_other', 'other'),
304: ('not_modified',),
305: ('use_proxy',),
306: ('switch_proxy',),
307: ('temporary_redirect', 'temporary_moved', 'temporary'),
308: ('permanent_redirect',
      'resume_incomplete', 'resume',), # These 2 to be removed in 3.0

# Client Error.
400: ('bad_request', 'bad'),
401: ('unauthorized',),
402: ('payment_required', 'payment'),
403: ('forbidden',),
404: ('not_found', '-o-'),
405: ('method_not_allowed', 'not_allowed'),
406: ('not_acceptable',),
407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'),
408: ('request_timeout', 'timeout'),
409: ('conflict',),
410: ('gone',),
411: ('length_required',),
412: ('precondition_failed', 'precondition'),
413: ('request_entity_too_large',),
414: ('request_uri_too_large',),
415: ('unsupported_media_type', 'unsupported_media', 'media_type'),
416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'),
417: ('expectation_failed',),
418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'),
421: ('misdirected_request',),
422: ('unprocessable_entity', 'unprocessable'),
423: ('locked',),
424: ('failed_dependency', 'dependency'),
425: ('unordered_collection', 'unordered'),
426: ('upgrade_required', 'upgrade'),
428: ('precondition_required', 'precondition'),
429: ('too_many_requests', 'too_many'),
431: ('header_fields_too_large', 'fields_too_large'),
444: ('no_response', 'none'),
449: ('retry_with', 'retry'),
450: ('blocked_by_windows_parental_controls', 'parental_controls'),
451: ('unavailable_for_legal_reasons', 'legal_reasons'),
499: ('client_closed_request',),

# Server Error.
500: ('internal_server_error', 'server_error', '/o\\', '✗'),
501: ('not_implemented',),
502: ('bad_gateway',),
503: ('service_unavailable', 'unavailable'),
504: ('gateway_timeout',),
505: ('http_version_not_supported', 'http_version'),
506: ('variant_also_negotiates',),
507: ('insufficient_storage',),
509: ('bandwidth_limit_exceeded', 'bandwidth'),
510: ('not_extended',),
511: ('network_authentication_required', 'network_auth', 'network_authentication')
get请求
没有参数

测试连接:http://httpbin.org/get,会判断如果如果是 GET 请求的话,会返回响应的 Request 信息。

import requests

response = requests.get("http://httpbin.org/get")
print(response.text)

运行结果:

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.22.0", 
    "X-Amzn-Trace-Id": "Root=1-5f5f0e95-cd68f9cadd5bdc14a9bd5868"
  }, 
  "origin": "111.122.73.198", 
  "url": "http://httpbin.org/get"
}

如果返回的内容为json数据可以,通过respons.json()进行打印数据,这样返回的格式为json格式。

有参数

可以通过在url里面添加参数,但是这样有点麻烦,而requests里面可以通过params进行处理。

import requests

params = {
    "name":"code"
}
response = requests.get("http://httpbin.org/get",params=params)
print(response.json())

运行结果:

{'args': {'name': 'code'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-5f5f0fdc-d0f3dc64548f4f0896b8b747'}, 'origin': '111.122.73.198', 'url': 'http://httpbin.org/get?name=code'}
获取二进制数据

图片、音频、视频这些文件都是本质上由二进制码组成的,由于有特定的保存格式和对应的解析方式,才可以看到这些形形色色的多媒体。所以想要抓取,那就需要拿到二进制码。

  1. GitHub 的站点图标为例

在爬取二进制数据时,应该使用content属性。

import requests
response = requests.get("https://github.com/favicon.ico")
print(response.text)
print((response.content))

运行结果:

�:�������������������������������O     

.....

接下来将二进制数据,保存为图片

import requests
response = requests.get("https://github.com/favicon.ico")
with open('favicon.ico','wb') as f:
    f.write(response.content)

运行后,会在同一目录下生产图标

img

添加Headers

通过requests里面的headers参数,就可以添加headers了。

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get("http://httpbin.org/get",headers=headers)
print(response.json())

实际情况下,添加headers有时候需要添加很多

如下:

image-20200914144859672

可以观察到,请求头的格式为A:B,由于粘贴复制过来后,还是需要进行修改为字典形式,有点麻烦。接下来就动手弄一个方便转化headers的python代码。

import requests


headers = """
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
Cache-Control: no-cache
Host: httpbin.org
Pragma: no-cache
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
"""


def str_to_dict(headers):
    return dict({header[0].strip(): header[1].strip() for header in
     [header.split(":") for header in headers.split('\n') if header]})

url = "http://httpbin.org/get"
response = requests.get(url=url,headers=str_to_dict(headers))
print(response.status_code)

运行结果:

200

解析headers的代码,如下:

def str_to_dict(headers):
    return dict({header[0].strip(): header[1].strip() for header in
     [header.split(":") for header in headers.split('\n') if header]})

这样就能够直接粘贴复制headers过来,自动解析为字典形式了。

post请求

post方法与get方法基本用法一样,只是请求方式不同。

没有表单数据
import requests

r = requests.post("http://httpbin.org/post")
print(r.text)
有表单数据

通过data传递表单数据。

import requests
data = {'name': 'germey', 'age': '22'}
r = requests.post("http://httpbin.org/post", data=data)
print(r.text)
其他请求方式
r = requests.put('http://httpbin.org/put')
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')
高级用法
上传文件

通过files关键字参数进行上传二进制数据,即文件。

import requests

files = {
	'file':open('185494.jpg','rb')
}
response = requests.post('http://httpbin.org/post',files=files)
print(response.text)
Cookies
  • 获取cookies
import requests

response = requests.get('https://www.baidu.com')
print(response.cookies)
for key,value in response.cookies.items():
    print(key+"="+value)

运行结果:

<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
BDORZ=27315
  • 通过使用cookies来维持登录

cookies在请求头里面进行设置的。

import requests

headers = {
    'Cookie': 'q_c1=31653b264a074fc9a57816d1ea93ed8b|1474273938000|1474273938000; d_c0="AGDAs254kAqPTr6NW1U3XTLFzKhMPQ6H_nc=|1474273938"; __utmv=51854390.100-1|2=registration_date=20130902=1^3=entry_date=20130902=1;a_t="2.0AACAfbwdAAAXAAAAso0QWAAAgH28HQAAAGDAs254kAoXAAAAYQJVTQ4FCVgA360us8BAklzLYNEHUd6kmHtRQX5a6hiZxKCynnycerLQ3gIkoJLOCQ==";z_c0=Mi4wQUFDQWZid2RBQUFBWU1DemJuaVFDaGNBQUFCaEFsVk5EZ1VKV0FEZnJTNnp3RUNTWE10ZzBRZFIzcVNZZTFGQmZn|1474887858|64b4d4234a21de774c42c837fe0b672fdb5763b0',
    'Host': 'www.zhihu.com',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36',
}
r = requests.get('https://www.zhihu.com', headers=headers)
print(r.text)

当然也可以通过 cookies 参数来设置,不过这样就需要构造 RequestsCookieJar 对象,而且需要分割一下 Cookies ,相对繁琐,不过效果是相同的,实例如下:

import requests

cookies = 'q_c1=31653b264a074fc9a57816d1ea93ed8b|1474273938000|1474273938000; d_c0="AGDAs254kAqPTr6NW1U3XTLFzKhMPQ6H_nc=|1474273938"; __utmv=51854390.100-1|2=registration_date=20130902=1^3=entry_date=20130902=1;a_t="2.0AACAfbwdAAAXAAAAso0QWAAAgH28HQAAAGDAs254kAoXAAAAYQJVTQ4FCVgA360us8BAklzLYNEHUd6kmHtRQX5a6hiZxKCynnycerLQ3gIkoJLOCQ==";z_c0=Mi4wQUFDQWZid2RBQUFBWU1DemJuaVFDaGNBQUFCaEFsVk5EZ1VKV0FEZnJTNnp3RUNTWE10ZzBRZFIzcVNZZTFGQmZn|1474887858|64b4d4234a21de774c42c837fe0b672fdb5763b0'
jar = requests.cookies.RequestsCookieJar()
headers = {
    'Host': 'www.zhihu.com',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
for cookie in cookies.split(';'):
    key, value = cookie.split('=', 1)
    jar.set(key, value)
r = requests.get('http://www.zhihu.com', cookies=jar, headers=headers)
print(r.text)
  • 新建了一个 RequestCookieJar 对象

  • 将复制下来的 Cookies 利用 split() 方法分割,利用 set() 方法设置好每一个 Cookie 的 key 和 value

  • 通过调用 Requests 的 get() 方法并传递给 cookies 参数即可,当然由于知乎本身的限制, headers 参数也不能少,只不过不需要在原来的 headers 参数里面设置 Cookie 字段了

会话维持

测试网址:http://httpbin.org/cookies/set/number/123456789

解决这个问题的主要方法就是维持同一个会话,也就是相当于打开一个新的浏览器选项卡而不是新开一个浏览器。但是又不想每次设置 Cookies,那该怎么办?这时候就有了新的利器 Session对象。

利用它,可以方便地维护一个会话,而且不用担心 Cookies 的问题,它会自动处理好

import requests

requests.get("http://httpbin.org/cookies/set/number/123456789")
r = requests.get("http://httpbin.org/cookies")
print(r.text)

运行结果:

{
  "cookies": {
  }
}

不能成功获取到设置的 Cookies

使用session测试

import requests

s  = requests.Session()
s.get("http://httpbin.org/cookies/set/number/123456789")
r = s.get("http://httpbin.org/cookies")
print(r.text)

运行结果:

{
  "cookies": {
    "number": "123456789"
  }
}

利用 Session 可以做到模拟同一个会话,而且不用担心 Cookies 的问题,通常用于模拟登录成功之后再进行下一步的操作。

SSL证书验证

测试网址:https://www.12306.cn

Requests 提供了证书验证的功能,当发送 HTTP 请求的时候,它会检查 SSL 证书,可以使用 verify 这个参数来控制是否检查此证书,其实如果不加的话默认是 True,会自动验证。

import requests

response = requests.get("https://www.12306.cn")
print(response.status_code)

运行结果:

requests.exceptions.SSLError:...

提示一个错误,叫做 SSLError,证书验证错误。所以如果请求一个 HTTPS 站点,但是证书验证错误的页面时,就会报这样的错误

如何避免这个错误,只需把 verify 这个参数设置为 False 即可。

import requests

response = requests.get("https://www.12306.cn",verify=False)
print(response.status_code)

运行结果:

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
200

不过发现报了一个警告,它提示建议给它指定证书。

可以通过设置忽略警告的方式来屏蔽这个警告:

import requests
import urllib3

urllib3.disable_warnings()
response = requests.get("https://www.12306.cn",verify=False)
print(response.status_code)

运行结果:

200

或者通过捕获警告到日志的方式忽略警告:

import requests
import logging

logging.captureWarnings(True)
response = requests.get("https://www.12306.cn",verify=False)
print(response.status_code)

可以指定一个本地证书用作客户端证书,可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组

import requests

response = requests.get('https://www.12306.cn',verify="E:/SRCA.crt")
print(response.status_code)
代理设置

设置代理,在 Requests 中需要用到 proxies 这个参数

import requests

# 代理池
proxies = {
    'http': 'http://10.10.1.10:3128',
    'https': 'http://10.10.1.10:1080',
}

r = requests.get('https://www.taobao.com',proxies=proxies)
print(r.status_code)

若代理需要使用 HTTP Basic Auth,可以使用类似http://user:password@host:port这样的语法来设置代理

import requests

proxies = {
    'https': 'http://user:password@10.10.1.10:3128/',
}
requests.get('https://www.taobao.com', proxies=proxies)

除了基本的 HTTP 代理,Requests 还支持 SOCKS 协议的代理。

需要安装 Socks 这个库,命令如下:

pip install "requests[socks]"

然后就可以使用 SOCKS 协议代理了

socks5://user:password@host:port
import requests

proxies = {
    'http': 'socks5://user:password@host:port',
    'https': 'socks5://user:password@host:port'
}
requests.get('https://www.taobao.com', proxies=proxies)
超时设置

设置超时时间需要用到 timeout 参数。这个时间的计算是发出 Request 到服务器返回 Response 的时间

import requests

r = requests.get('https://www.taobao.com', timeout=1)
print(r.status_code)

通过这样的方式,可以将超时时间设置为 1 秒,如果 1 秒内没有响应,那就抛出异常。

实际上请求分为两个阶段,即 connect(连接)和 read(读取)。

上面的设置 timeout 值将会用作 connect 和 read 二者的 timeout 总和。

如果要分别指定,就可以传入一个元组:

r = requests.get('https://www.taobao.com', timeout=(5, 11))

如果想永久等待,那么可以直接将 timeout 设置为 None,或者不设置直接留空,因为默认是 None。这样的话,如果服务器还在运行,但是响应特别慢,那就慢慢等吧,它永远不会返回超时错误的。

r = requests.get('https://www.taobao.com', timeout=None)
或者
r = requests.get('https://www.taobao.com')
身份认证

在访问网页的时候,有可能遇到这样的页面认证,可以使用Requests字典的身份认证功能。

image-20200914152509532

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'password'))
print(r.status_code)

更简便的认证,可以直接传一个元组,它会默认使用 HTTPBasicAuth 这个类来认证

import requests

r = requests.get('http://localhost:5000', auth=('username', 'password'))
print(r.status_code)

Requests 还提供了其他的认证方式,如 OAuth 认证,不过需要安装 oauth 包

pip install requests_oauthlib

使用OAuth1方法认证

import requests
from requests_oauthlib import OAuth1

url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET',
              'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
requests.get(url,auth=auth)

requests_oauthlib官方文档

Prepared Request

当从 API 或者会话调用中收到一个 Response 对象时,request 属性其实是使用了 PreparedRequest。有时在发送请求之前,需要对 body 或者 header (或者别的什么东西)做一些额外处理。

from requests import Request,Session

url = 'http://httpbin.org/post'
data = {
    'name':'angle',
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36'
}
s = Session()
req = Request('POST',url,data=data,headers=headers)
prepped = s.prepare_request(req)
r = s.send(prepped)
print(r.text)

引入 Request,然后用 url、data、headers 参数构造了一个 Request 对象,需要再调用 Session 的 prepare_request() 方法将其转换为一个 Prepared Request 对象,然后调用 send() 方法发送即可

有了 Request 这个对象,就可以将一个个请求当做一个独立的对象来看待,这样在进行队列调度的时候会非常方便

正则表达式

传送门

实战-抓取猫眼电影排行
任务

猫眼电影地址

  1. 利用 Requests 和正则表达式来抓取猫眼电影 TOP100

  2. 提取出猫眼电影 TOP100 榜的电影名称、时间、评分、图片等信息,提取的结果以文件形式保存下来。

分析

打开猫眼电影可以查看榜单信息

image-20200914161802806

在图中可以清楚地看到影片的信息,页面中显示的信息有影片名称、主演、上映时间、上映地区、评分、图片等。

之后点击下一页,观察url的变化。

image-20200914161921847

image-20200914161839735

可以发现http://maoyan.com/board/4?offset=10比之前的url多了一个参数offset,参数值为10,目前显示的排行数据11~20,可以判断offset是一个偏移量的参数再点击下一页,发现页面的 URL 变成了:http://maoyan.com/board/4?offset=20,参数 offset 变成了 20,而显示的结果是排行 21-30 的电影。

可以判断offset是一个偏移量,如果偏移值为n,则当前页面的序号为n+1到n+10,这样就可以更根据offset获取top100的所有电影信息了。

抓取
抓取首页

定义一个get_frist_page()函数方法,实现抓取首页,代码实现,并通过str_to_dict()函数方法,解析headers。

import requests,re,time

headers = """
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8
Cookie: __mta=213316523.1600064586376.1600071552350.1600071714950.12; uuid_n_v=v1; uuid=BF1A8980F65211EA91B4F5F3486B36AE5527F4FDA8BA451BBFAF2262F89F4D1E; _csrf=6262310ffe9bccdefebbb75223f0a636294a6118f10201d6207cff27cfa8c309; mojo-uuid=f688f38edd40a41769114ca40701dd6e; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1600064586; _lx_utm=utm_source%3Dgoogle%26utm_medium%3Dorganic; _lxsdk_cuid=1748b48012ac8-0c9d0a9c72ac5c-3b634404-144000-1748b48012bc8; _lxsdk=BF1A8980F65211EA91B4F5F3486B36AE5527F4FDA8BA451BBFAF2262F89F4D1E; mojo-session-id={"id":"1e4cb65fc0ee3717c231a3e0ff9cb3fa","time":1600071190284}; __mta=213316523.1600064586376.1600071198156.1600071412671.4; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1600071715; mojo-trace-id=18; _lxsdk_s=1748bacc849-451-484-5fb%7C%7C27
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
"""

def str_to_dict(headers):
    return dict({header[0].strip(): header[1].strip() for header in
     [header.split(":") for header in headers.split('\n') if header]})

def get_frist_page(url):
    response = requests.get(url=url,headers=str_to_dict(headers))
    if response.status_code == requests.codes.ok:
        return response.text
    return None

def run(url):
    response = get_frist_page(url=url)
    print(response)

if __name__ == "__main__":
    url = "https://maoyan.com/board/4"
    run(url=url)

一定要加上请求头,不然猫眼网站会禁止访问

使用正则提取数据

现在抓取了首页,需要进一步抓取相关信息,接下来回到网页看一下页面的真实源码,在开发者工具中 Network 监听,然后查看一下源代码,注意这里不要在 Elements 选项卡直接查看源码,此处的源码可能经过 JavaScript 的操作而和原始请求的不同,需要从Network选项卡部分查看原始请求得到的源码。

image-20200914162959814

先看下个电影的相关内容

<dd>
	<i class="board-index board-index-1">1</i>
	<a href="/films/13824" title="射雕英雄传之东成西就" class="image-link" data-act="boarditem-click" data-val="{movieId:13824}">
		<img src="//s3plus.meituan.net/v1/mss_e2821d7f0cfe4ac1bf9202ecf9590e67/cdn-prod/file:5788b470/image/loading_2.e3d934bf.png"
		 alt="" class="poster-default" />
		<img data-src="https://p0.meituan.net/movie/53d18b640f8af0c47d7c95488450c265388754.jpg@160w_220h_1e_1c" alt="射雕英雄传之东成西就"
		 class="board-img" />
	</a>
	<div class="board-item-main">
		<div class="board-item-content">
			<div class="movie-item-info">
				<p class="name"><a href="/films/13824" title="射雕英雄传之东成西就" data-act="boarditem-click" data-val="{movieId:13824}">射雕英雄传之东成西就</a></p>
				<p class="star">
					主演:张国荣,梁朝伟,张学友
				</p>
				<p class="releasetime">上映时间:1993-02-05(中国香港)</p>
			</div>
			<div class="movie-item-number score-num">
				<p class="score"><i class="integer">8.</i><i class="fraction">8</i></p>
			</div>

		</div>
	</div>
</dd>

现在需要从这段里面提取需要的信息,书写正则表达式

排名信息:<i.*?board-index.*?>(.*?)</i>

进一步编写:

封面图片:<img.*?data-src="(.*?)"

继续:

电影名称:<p.*?name.*?title="(.*?)"

依次类推:

所有信息:<i.*?board-index.*?>(.*?)</i>.*?<img.*?data-src="(.*?)".*?<p.*?name.*?title="(.*?)".*?/p>.*?<p.*?releasetime">(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>

这样就可以提取第一页的内容,代码如下:

def parse_first_page(response):
    pattern = '<i.*?board-index.*?>(.*?)</i>.*?<img.*?data-src="(.*?)".*?<p.*?name.*?title="(.*?)".*?/p>.*?<p.*?releasetime">(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>'
    pattern = re.compile(pattern,re.S)
    items = re.findall(pattern,response)
    for item in items:
        print(item)

def run(url):
    response = get_frist_page(url=url)
    parse_first_page(response)

运行结果:

('1', 'https://p0.meituan.net/movie/53d18b640f8af0c47d7c95488450c265388754.jpg@160w_220h_1e_1c', '射雕英雄传之东成西就', '上映时间:1993-02-05(中国香港)', '8.', '8')
('2', 'https://p0.meituan.net/movie/df15efd261060d3094a73ef679888d4f238149.jpg@160w_220h_1e_1c', '十二怒汉', '上映时间:1957-04-13(美国)', '9.', '1')
('3', 'https://p1.meituan.net/movie/6a964e9cee699267053bd6a4bf6f2671195394.jpg@160w_220h_1e_1c', '剪刀手爱德华', '上映时间:1990-12-06(美国)', '8.', '8')
('4', 'https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c', '乱世佳人', '上映时间:1939-12-15(美国)', '9.', '1')
('5', 'https://p1.meituan.net/movie/226f647bd2bf6f45d8d503c0ae8d920c341293.jpg@160w_220h_1e_1c', '初恋这件小事', '上映时间:2012-06-05', '8.', '8')
('6', 'https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c', '泰坦尼克号', '上映时间:1998-04-03', '9.', '4')
('7', 'https://p0.meituan.net/movie/b3defc07dfaa1b6f5b74852ce38a3f8f242792.jpg@160w_220h_1e_1c', '搏击俱乐部', '上映时间:1999-09-10(意大利)', '8.', '8')
('8', 'https://p0.meituan.net/movie/609e45bd40346eb8b927381be8fb27a61760914.jpg@160w_220h_1e_1c', '海上钢琴师', '上映时间:2019-11-15', '9.', '3')
('9', 'https://p1.meituan.net/movie/0b0d45b58946078dd24d4945dd6be3b51329411.jpg@160w_220h_1e_1c', '甜蜜蜜', '上映时间:2015-02-13', '9.', '2')
('10', 'https://p0.meituan.net/movie/8112a8345d7f1d807d026282f2371008602126.jpg@160w_220h_1e_1c', '肖申克的救赎', '上映时间:1994-09-10(加拿大)', '9.', '5')

由于数据看起来比较杂乱,需要处理一下,遍历生成为字典

def parse_first_page(response):
    pattern = '<i.*?board-index.*?>(.*?)</i>.*?<img.*?data-src="(.*?)".*?<p.*?name.*?title="(.*?)".*?/p>.*?<p.*?releasetime">(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>'
    pattern = re.compile(pattern,re.S)
    items = re.findall(pattern,response)
    for item in items:
        yield {
            'index': item[0],
            'image': item[1],
            'title': item[2].strip(),
            'time': item[3].strip()[5:] if len(item[3]) > 5 else '',
            'score': item[4].strip() + item[5].strip()
        }

def run(url):
    response = get_frist_page(url=url)
    items = parse_first_page(response)
    for item in items:
        print(item)
存储数据

把数据存储到文本文件中,在这里直接写入到一个文本文件中,通过 json 库的 dumps() 方法实现字典的序列化,并指定 ensure_ascii 参数为 False,这样可以保证输出的结果是中文形式而不是 Unicode 编码。

# 存储数据
def save_to_json(content):
    with open('data.txt','a',encoding='utf-8') as f:
        # print(type(json.dumps(content)))
        f.write(json.dumps(content,ensure_ascii=False,))

def run(url):
    response = get_frist_page(url=url)
    items = parse_first_page(response)
    for item in items:
        save_to_json(item)
实战-分析ajax爬取今日头条街拍美图
什么是Ajax

Ajax,全称为 Asynchronous JavaScript and XML,即异步的 JavaScript 和 XML。

Ajax 请求:数据的加载是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面加载完后会会再向服务器请求某个接口获取数据,然后数据再被处理才呈现到网页上。

w3c官网#ajax

Ajax分析方法
查看请求

开发者工具(F12) > Network

过滤请求

点击XHR,筛选ajax请求

image-20200914170747898

Ajax结果提取
分析请求

分析网址:https://www.toutiao.com/search/?keyword=%E8%A1%97%E6%8B%8D

打开开发者工具 > Network面板>选中XHR,筛选ajax请求

image-20200914170916708

分析url参数

image-20200914171407942

image-20200914171426866

可以后面多了一个offset参数在变化,偏移量为20。其中keyword为搜索关键字,count为显示的数据条数。

抓取
获取数据
headers = """
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
"""

def str_to_dict(headers):
    return dict({header[0].strip(): header[1].strip() for header in
     [header.split(":") for header in headers.split('\n') if header]})

def get_page(offset=0):
    params = {
        'offset': offset,
        'format': 'json',
        'keyword': '街拍',
        'autoload': 'true',
        'count': '20',
        'cur_tab': '1',
        'from': 'search_tab',
    }
    try:
        response = requests.get(url,params=params,headers=str_to_dict(headers))
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        print(e.args)
获取图片
def get_images(response):
    if response:
        items = response.get("data")
        if items:
            for item in items:
                title = item.get("title")
                images = item.get("image_list")
                if title and images:
                    for image in images:
                            yield {
                                'image': image.get("url"),
                                'title': title,
                            }
存储图片
def save_images(item):
    title = item.get("title")
    if not os.path.exists(title):
        os.mkdir(title)
    try:
        image = item.get("image")
        response = requests.get("http:"+image)
        if response.status_code == 200:
            # 读取二进制流数据
            content = response.content
            # 利用md5函数判断重复
            filepath = "{0}/{1}.{2}".format(title,md5(content).hexdigest(),'jpg')
            if not os.path.exists(filepath):
                with open(filepath,'wb' ) as f:
                    f.write(response.content)
            else:
                print("Already Download {}".format(filepath))
    except requests.ConnectionError as e:
        print("Failed to Save Image")
主函数
def main(offset=0):
    response = get_page(offset)
    for item in get_images(response):
        print(item)
        save_images(item)
启动
import requests,os
from urllib.parse import urlencode
from multiprocessing import Pool
from hashlib import md5

...

GROUP_START = 1
GROUP_END = 20

def get_page(offset=0):
	...

def get_images(response):
	...


def save_images(item):
	...

def main(offset=0):
	...

if __name__ == "__main__":
    # 开启进程池
    pool = Pool()
    groups = [x*20 for x in range(GROUP_START,GROUP_END+1)]
    print(groups)
    pool.map(main,groups)
    pool.close()
    pool.join()

selenium

安装
pip install selenium

但是需要用浏览器来配合selenium使用,需要进行一些配置,才可以使用selenium

ChromeDriver
下载

selenium对chrome浏览器操作,需要进行以下配置

根据chrome版本进行下载ChromeDriver。

image-20200917164443936

ChromeDriver下载链接

根据版本号,找到对应下载版本

image-20200917164551015

配置环境变量

之后将下载后,解压得到exe文件进行配置相关的环境变量。

在windows平台下,直接把可执行文件拖入python的Scripts目录下,这样就配置到环境变量中了

在 Linux、Mac 下,需要将可执行文件配置到环境变量或将文件移动到属于环境变量的目录里。

例如移动文件到 /usr/bin 目录,首先命令行进入其所在路径,然后将其移动到 /usr/bin:

sudo mv chromedriver /usr/bin

当然也可以将 ChromeDriver 配置到 $PATH,首先可以将可执行文件放到某一目录,目录可以任意选择,例如将当前可执行文件放在 /usr/local/chromedriver 目录下,接下来可以修改 ~/.profile 文件,命令如下:

export PATH="$PATH:/usr/local/chromedriver"

保存然后执行:

source ~/.profile
验证

在命令行下输入chromedriver命令进行验证

image-20200917165044531

然后在程序中测试

from selenium import webdriver
browser = webdriver.Chrome()

如果有chrome浏览器自动打开,就代表配置成功。

GeckoDriver
下载

selenium对firefox浏览器操作,需要进行以下配置

GeckoDriver下载链接

image-20200917165455499

配置环境变量

下载完成后将geckodriver可执行文件配置到环境变量中

在windows平台下,直接把可执行文件拖入python的Scripts目录下,这样就配置到环境变量中了

在 Linux、Mac 下,需要将可执行文件配置到环境变量或将文件移动到属于环境变量的目录里。

例如移动文件到 /usr/bin 目录,首先命令行进入其所在路径,然后将其移动到 /usr/bin:

sudo mv geckodriver /usr/bin

当然也可以将 GeckoDriver 配置到 $PATH,首先可以将可执行文件放到某一目录,目录可以任意选择,例如将当前可执行文件放在/usr/local/geckodriver目录下,接下来可以修改 ~/.profile 文件,命令如下:

vi ~/.profile

添加如下一句配置:

export PATH="$PATH:/usr/local/geckodriver"

保存然后执行如下命令即可完成配置:

source ~/.profile
验证

在命令行下输入GeckoDriver命令进行验证

image-20200917165640546

然后在程序中测试

from selenium import webdriver
browser = webdriver.Firefox()

如果有Firefox浏览器自动打开,就代表配置成功

PhantomJS
下载

PhantomJS是一个无界面的浏览器.selenium支持PhantomJS,这样在运行的时候就不会弹出一个浏览器。

image-20200917165946807

phantomjs下载链接

配置环境变量

配置环境和前面一样

验证

在命令行下输入PhantomJS命令进行验证有类似结果输出就代表配置环境成功

image-20200917171753957

然后在程序中测试

from selenium import webdriver
browser = webdriver.PhantomJS()
browser.get('https://www.baidu.com')
print(browser.current_url)

运行后会发现没有浏览器打开,但实际上phantomjs已经运行起来了

image-20200917171902750

这里访问了百度,如果将当前url打印出来了就代表PhantomJS配置成功了

用途

selenium能够模拟用户打开浏览器,从而获取数据,能够解决动态渲染页面(ajax)的问题。

文档
用法
基本使用
  • 导入模块
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
  • 创建webdriver实例
driver = webdriver.Chrome()
  • 发起请求

driver.get 方法将打开URL中填写的地址,WebDriver 将等待, 直到页面完全加载完毕(其实是等到”onload” 方法执行完毕),然后返回继续执行脚本。

driver.get("http://www.baidu.com/")
  • 查找元素
search = driver.find_element_by_id("kw")
  • 输入内容以及清除内容、按下enter键
search.clear() # 清除
search.send_keys("python") # 输入
search.send_keys(Keys.RETURN) # enter键
  • 关闭浏览器
driver.close()

如果想要浏览器一直显示,就不要输入这句。

  • 点击
search.click() # 模拟鼠标的点击
填写表单
测试网站

测试url

image-20200917184604820

image-20200917184615911

导入模块
from selenium.webdriver.support.ui import Select
Select类方法
方法名说明
options返回属于此选择标记的所有选项的列表
选择
select_by_value通过 value 值来获取 select 列表的标签名
select_by_index通过 下标 来获取 select 列表的标签名
select_by_visible_text通过 可见的文本内容 来获取 select
取消选择
deselect_by_index(index)
deselect_by_value(value)
deselect_by_visible_text(text)
deselect_all()

select框

<select id="s1Id">
<option></option>
<option value="o1" id="id1">o1</option>
<option value="o2" id="id2">o2</option>
<option value="o3" id="id3">o3</option>
</select>
实例
driver.get("http://sahitest.com/demo/selectTest.htm")

select1 = driver.find_element_by_id("s1Id")

s1 = Select(select1)
s1.select_by_index(1)  # 选择第二项选项:o1
s1.select_by_value("o2")  # 选择value="o2"的项
s1.select_by_visible_text("o3")  # 选择text="o3"的值,即在下拉时我们可以看到的文本
拖拽

image-20200917185613153

image-20200917185635442

from selenium import webdriver
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
url = "http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable"
driver.get(url)

source = driver.find_element_by_css_selector("#draggable") # 拖动的物品
target = driver.find_element_by_css_selector("#droppable") # 需要拖到的位置

# 创建动作链的实例
actions = ActionChains(driver)

# 调用拖拽方法
actions.drag_and_drop(source,target)

# 执行动作
actions.perform()
切换窗口、框架
  • 切换窗口
import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait  # 等待页面加载某些元素
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 获取driver
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

# 发请求
driver.get('https://www.baidu.com')

# 定位标签并输入值然后点击
driver.find_element_by_id('kw').send_keys('python.org')
time.sleep(1)
driver.find_element_by_id('su').click()
# 在新窗口中,点击结果标签

wait.until(EC.presence_of_element_located((By.LINK_TEXT, 'Welcome to Python.org'))).click()
# driver.find_element_by_link_text('Welcome to Python.org').click()

# 所有打开的窗口都存在这个数组中
# print(driver.window_handles)

# 根据数组下标索引切换窗口
time.sleep(3)
driver.switch_to.window(driver.window_handles[1])
time.sleep(3)
driver.switch_to.window(driver.window_handles[0])

image-20200917191355424

  • 切换iframe框架

image-20200917185935833

from selenium import webdriver
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
driver.get("https://qzone.qq.com/")
# 根据id切换iframe
driver.switch_to.frame("login_frame")

# 切换输入方式
driver.find_element_by_id("switcher_plogin").click()

# 用户、密码、提交按钮
username = driver.find_element_by_id("u")
password = driver.find_element_by_id("p")
button = driver.find_element_by_id("login_button")

username.clear()
password.clear()

username.send_keys("username")
password.send_keys("password")
button.click()

image-20200917190358666

返回父frame:

driver.switch_to_default_content()
访问浏览器历史记录

在浏览历史中前进和后退你可以使用:

driver.forward()
driver.back()
操作cookies

添加cookies

cookie = {'name' : 'foo', 'value' : 'bar'}

# 发请求
driver.get('https://www.baidu.com')

driver.add_cookie(cookie)

image-20200917191708354

获取所有当前URL下可获得的Cookies

print(driver.get_cookies())
查找元素
driver.find_element_by_id()通过ID查找元素
driver.find_element_by_name()通过Name查找元素
driver.find_element_by_xpath()通过XPath查找元素
driver.find_element_by_link_text()通过链接文本获取超链接
driver.find_element_by_tag_name()过标签名查找元素
driver.find_element_by_class_name()通过Class name 定位元素
driver.find_element_by_css_selector()通过CSS选择器查找元素

其中xpath用法

表达式描述
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
..选取当前节点的父节点
@选取属性
*通配符,选择所有元素节点与元素名
@*选取所有属性
[@attrib]选取具有给定属性的所有元素
[@attrib='value]选取给定属性具有给定值的所有元素
[tag]选取所有具有指定元素的直接子节点
[tag="text"]选取所有具有指定元素并且文本内容是text节点
等待页面加载完成

现在的大多数的Web应用程序是使用Ajax技术。当一个页面被加载到浏览器时, 该页面内的元素可以在不同的时间点被加载。这使得定位元素变得困难, 如果元素不再页面之中,会抛出 ElementNotVisibleException 异常。 使用 waits, 可以解决这个问题。waits提供了一些操作之间的时间间隔- 主要是定位元素或针对该元素的任何其他操作。

Selenium Webdriver 提供两种类型的waits - 隐式和显式。 显式等待会让WebDriver等待满足一定的条件以后再进一步的执行。 而隐式等待让Webdriver等待一定的时间后再才是查找某元素。

显式等待
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
try:
# presence_of_element_located为加载条件
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "kw"))
    )
finally:
    driver.close()
    // pass
所有的加载条件
等待条件含义
title_is标题是某内容
title_contains标题包含某内容
presence_of_element_located节点加载出,传入定位元组,如(By.ID, 'p')
visibility_of_element_located节点可见,传入定位元组
visibility_of可见,传入节点对象
presence_of_all_elements_located所有节点加载出
text_to_be_present_in_element某个节点文本包含某文字
text_to_be_present_in_element_value某个节点值包含某文字
frame_to_be_available_and_switch_to_it frame加载并切换
invisibility_of_element_located节点不可见
element_to_be_clickable节点可点击
staleness_of判断一个节点是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected节点可选择,传节点对象
element_located_to_be_selected节点可选择,传入定位元组
element_selection_state_to_be传入节点对象以及状态,相等返回True,否则返回False
element_located_selection_state_to_be传入定位元组以及状态,相等返回True,否则返回False
alert_is_present是否出现Alert
隐式等待

如果某些元素不是立即可用的,隐式等待是告诉WebDriver去等待一定的时间后去查找元素。 默认等待时间是0秒,一旦设置该值,隐式等待是设置该WebDriver的实例的生命周期。

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("https://www.baidu.com/")
search = driver.find_element_by_id("kw")
执行javascript

模拟执行javascript,使用execute_script()方法实现

from selenium import webdriver

browser = webdriver.Chrome()
browser.get("https://www.zhihu.com/explore")
# 将进度条下拉到最底部
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
# 弹出提示框
browser.execute_script('alert("To Bottom")')
获取节点信息
获取属性

使用get_attribute()方法来获取节点的属性

from selenium import webdriver

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
logo = browser.find_element_by_id("zh-top-link-logo")
print(logo)
print(logo.get_attribute("class"))

运行结果:

<selenium.webdriver.remote.webelement.WebElement (session="036f1edccab08bbc5ca2b8f02accbb04", element="0.40649588367097245-1")>
zu-top-link-logo
获取文本值

通过text属性获取文本信息

from selenium import webdriver

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
input = browser.find_element_by_id("zu-top-add-question")
print(input.text)

运行结果:

提问
获取ID、位置、标签名、大小
  • id属性:获取节点id
  • location:获取节点再页面中的相对位置
  • tag_name:获取标签名称
  • size:获取节点的大小
from selenium import webdriver

browser = webdriver.Chrome()
url = "https://www.zhihu.com/explore"
browser.get(url)
input = browser.find_element_by_id("zu-top-add-question")
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)

运行结果:

0.4994837841126192-1
{'x': 683, 'y': 7}
button
{'height': 32, 'width': 66}
异常处理
from selenium import webdriver
from selenium.common.exceptions import TimeoutException, NoSuchElementException

browser = webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')
except TimeoutException:
    print('Time Out')
try:
    browser.find_element_by_id('hello')
except NoSuchElementException:
    print('No Element')
finally:
    browser.close()

运行结果:

No Element
设置代理
  • 连接无用户密码认证的代理
from selenium import webdriver

chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument('--proxy-server=http://ip:port')  
driver = webdriver.Chrome(chrome_options=chromeOptions)
  • 有用户名和密码的连接
import string
import zipfile
from selenium import webdriver

# 代理服务器(ip+port)
proxyHost = "ip"
proxyPort = "port"
# 代理隧道验证信息(账号+密码)
proxyUser = "user"
proxyPass = "password"


def create_proxy_auth_extension(proxy_host, proxy_port, proxy_username, proxy_password, scheme='http', plugin_path=None):
    if plugin_path is None:
        plugin_path = r'{}_{}@http-dyn.dobel.com_9020.zip'.format(proxy_username, proxy_password)

    manifest_json = """
    {
        "version": "1.0.0",
        "manifest_version": 2,
        "name": "Dobel Proxy",
        "permissions": [
            "proxy",
            "tabs",
            "unlimitedStorage",
            "storage",
            "<all_urls>",
            "webRequest",
            "webRequestBlocking"
        ],
        "background": {
            "scripts": ["background.js"]
        },
        "minimum_chrome_version":"22.0.0"
    }
    """

    background_js = string.Template(
        """
        var config = {
            mode: "fixed_servers",
            rules: {
                singleProxy: {
                    scheme: "${scheme}",
                    host: "${host}",
                    port: parseInt(${port})
                },
                bypassList: ["foobar.com"]
            }
          };

        chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});

        function callbackFn(details) {
            return {
                authCredentials: {
                    username: "${username}",
                    password: "${password}"
                }
            };
        }

        chrome.webRequest.onAuthRequired.addListener(
            callbackFn,
            {urls: ["<all_urls>"]},
            ['blocking']
        );
        """
    ).substitute(
        host=proxy_host,
        port=proxy_port,
        username=proxy_username,
        password=proxy_password,
        scheme=scheme,
    )

    with zipfile.ZipFile(plugin_path, 'w') as zp:
        zp.writestr("manifest.json", manifest_json)
        zp.writestr("background.js", background_js)

    return plugin_path


proxy_auth_plugin_path = create_proxy_auth_extension(
    proxy_host=proxyHost,
    proxy_port=proxyPort,
    proxy_username=proxyUser,
    proxy_password=proxyPass)

option = webdriver.ChromeOptions()
# option.add_argument('--no-sandbox')
# option.add_argument('--disable-gpu')
# option.add_argument("--start-maximized")
option.add_extension(proxy_auth_plugin_path)

drive = webdriver.Chrome(chrome_options=option)

drive.get("https://www.baidu.com/")



print(drive.page_source)

# drive.close()
设置header
设置phantomjs请求头
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap["phantomjs.page.settings.userAgent"] = (
"Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36"
)
driver = webdriver.PhantomJS(desired_capabilities=dcap)
driver.get("https://www.baidu.com/")
driver.quit()
设置chrome请求头
from selenium import webdriver
# 进入浏览器设置
options = webdriver.ChromeOptions()
# 设置中文
options.add_argument('lang=zh_CN.UTF-8')
# 更换头部
options.add_argument('user-agent="Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20"')
browser = webdriver.Chrome(chrome_options=options)
url = "https://www.baidu.com/"
browser.get(url)
browser.quit()
细节
设置phantomjs-图片不加载
from selenium import webdriver

options = webdriver.ChromeOptions()
prefs = {
    'profile.default_content_setting_values': {
        'images': 2
    }
}
options.add_experimental_option('prefs', prefs)
browser = webdriver.Chrome(chrome_options=options)

# browser = webdriver.Chrome()
url = "http://image.baidu.com/"
browser.get(url)
browser.quit()
设置chrome为无界面浏览
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

#这个是一个用来控制chrome以无界面模式打开的浏览器
#创建一个参数对象,用来控制chrome以无界面的方式打开
chrome_options = Options()
#后面的两个是固定写法 必须这么写
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

#创建浏览器对象
browser = webdriver.Chrome(chrome_options=chrome_options)

url ='http://www.baidu.com/'

browser.get(url)
time.sleep(3)
# 将页面进行截图保存
browser.save_screenshot('baid.png')
browser.quit()
  • browser.save_screenshot('baid.png'):保存当前页面
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值