Python爬虫

爬虫知识

requests模块

安装:pip install requests

requests模块发送get请求

1
2
3
4
5
6
7
8
9
10
11
12
# 1.2.1-简单的代码实现
import requests

# 目标url
url = 'https://www.baidu.com'

# 向目标url发送get请求
response = requests.get(url)

# 打印响应内容
print(response.text)
print(response.content.decode())

response

response.text 和response.content区别

response.text

  • 类型:str
  • 解码类型: requests模块自动根据HTTP 头部对响应的编码作出有根据的推测,推测的文本编码

response.content

  • 类型:bytes
  • 解码类型: 没有指定

属性

response = requests.get(url)中response是发送请求获取的响应对象;response响应对象中除了text、content获取响应内容以外还有其它常用的属性或方法:

  • response.url响应的url;有时候响应的url和请求的url并不一致
  • response.status_code 响应状态码
  • response.request.headers 响应对应的请求头
  • response.headers 响应头
  • response.request._cookies 响应对应请求的cookie;返回cookieJar类型
  • response.cookies 响应的cookie(经过了set-cookie动作;返回cookieJar类型
  • response.json()自动将json字符串类型的响应内容转换为python对象(dict or list
1
2
3
4
# 解码,默认utf-8
response.content.decode()
# 使用GBK解码
response.content.decode("GBK")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1.2.3-response其它常用属性
import requests

# 目标url
url = 'https://www.baidu.com'

# 向目标url发送get请求
response = requests.get(url)

# 打印响应内容
print(response.url) # 打印响应的url
print(response.status_code) # 打印响应的状态码
print(response.request.headers) # 打印响应对象的请求头
print(response.headers) # 打印响应头
print(response.request._cookies) # 打印请求携带的cookies
print(response.cookies) # 打印响应中携带的cookies

携带参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

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

headers = {
"User-Agent": "请求头",
# 从浏览器中复制过来的Cookie
'Cookie': 'xxx这里是复制过来的cookie字符串'
}

# 请求参数是一个字典 即wd=python
kw = {'wd': 'python'}

# 请求头中带上User-Agent,模拟浏览器发送请求,带上请求参数发起请求,获取响应
response = requests.get(url, headers=headers, params=kw)

cookies使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url = 'https://github.com/USER_NAME'

# 构造请求头字典
headers = {
'User-Agent': '请求头'
}
# 构造cookies字典
cookies_str = '从浏览器中copy过来的cookies字符串'

cookies_dict = {cookie.split('=')[0]:cookie.split('=')[-1] for cookie in cookies_str.split('; ')}

# 请求头参数字典中携带cookie字符串
resp = requests.get(url, headers=headers, cookies=cookies_dict)

print(resp.text)

cookieJar对象转换为cookies字典的方法

1
2
# requests.utils.dict_from_cookiejar函数返回cookies字典
cookies_dict = requests.utils.dict_from_cookiejar(response.cookies)

timeout使用

1
2
3
4
import requests

url = 'https://twitter.com'
response = requests.get(url, timeout=3) # 设置超时时间

代理

1
2
3
4
5
proxies = { 
"http": "http://12.34.56.79:9527",
"https": "https://12.34.56.79:9527",
}
response = requests.get(url, proxies=proxies)

忽略CA证书

1
2
3
import requests
url = "https://sam.huat.edu.cn:8443/selfservice/"
response = requests.get(url,verify=False)

jsonpath模块

安装:pip install jsonpath

1
2
from jsonpath import jsonpath
ret = jsonpath(a, 'jsonpath语法规则字符串')

jsonpath的方法

jsonpath使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
book_dict = { 
"store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}

from jsonpath import jsonpath

print(jsonpath(book_dict, '$..author')) # 如果取不到将返回False # 返回列表,如果取不到将返回False

xpath

xpath_helper插件安装

xpath节点

xpath节点

xpath中节点的关系

xpath基础语法

  1. XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。
  2. 这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
  3. 使用chrome插件选择标签时候,选中时,选中的标签会添加属性class=”xh-highlight”
表达式 描述
nodename 选中该元素。
/ 从根节点选取、或者是元素和元素间的过渡。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
text() 选取文本。

选择所有的h2下的文本://h2/text()

获取所有的a标签的href://a/@href

获取html下的head下的title的文本:/html/head/title/text()

获取html下的head下的link标签的href:/html/head/link/@href

节点修饰语法

下标

  • 在xpath中,第一个元素的位置是1
  • 最后一个元素的位置是last()
  • 倒数第二个是last()-1
路径表达式 结果
//title[@lang=”eng”] 选择lang属性值为eng的所有title元素
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()>1] 选择bookstore下面的book元素,从第二个开始选择
//book/title[text()=’Harry Potter’] 选择所有book下的title元素,仅仅选择文本为Harry Potter的title元素
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
通配符 描述
* 匹配任何元素节点。
node() 匹配任何类型的节点。

lxml模块

安装:pip/pip3 install lxml

lxml模块的使用

  1. 导入lxml 的 etree 库

    from lxml import etree

  2. 利用etree.HTML,将html字符串(bytes类型或str类型)转化为Element对象,Element对象具有xpath的方法,返回结果的列表

    1
    2
    html = etree.HTML(text) 
    ret_list = html.xpath("xpath语法规则字符串")
  3. xpath方法返回列表的三种情况

    • 返回空列表:根据xpath语法规则字符串,没有定位到任何元素
    • 返回由字符串构成的列表:xpath字符串规则匹配的一定是文本内容或某属性的值
    • 返回由Element对象构成的列表:xpath规则字符串匹配的是标签,列表中的Element对象可以继续进行xpath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from lxml import etree
text = '''
<div>
<ul>
<li class="item-1">

</li>
<li class="item-1">

</li>
<li class="item-inactive">

</li>
<li class="item-1">

</li>
<li class="item-0">
a href="link5.html">fifth item</a>
</ul>
</div>
'''

html = etree.HTML(text)

#获取href的列表和title的列表
href_list = html.xpath("//li[@class='item-1']/a/@href")
title_list = html.xpath("//li[@class='item-1']/a/text()")

#组装成字典
for href in href_list:
item = {}
item["href"] = href
item["title"] = title_list[href_list.index(href)]
print(item)

其他

  • lxml.etree.HTML(html_str)可以自动补全标签

  • lxml.etree.tostring函数可以将转换为Element对象再转换回html字符串

  • 爬虫如果使用lxml来提取数据,应该以lxml.etree.tostring的返回结果作为提取数据的依据

selenium使用

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium 可以直接调用浏览器,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器),可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏等

selenium安装

python安装:pip3 install selenium

chrome安装

https://npm.taobao.org/mirrors/chromedriver下载对应版本的

解压压缩包后获取python代码可以调用的谷歌浏览器的webdriver可执行文件

windows环境下需要将 chromedriver.exe 所在的目录设置为path环境变量中的路径

linux/mac环境下,将 chromedriver 所在的目录设置到系统的PATH环境值中

selenium使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import time
from selenium import webdriver

# 通过指定chromedriver的路径来实例化driver对象,chromedriver放在当前目录。
# driver = webdriver.Chrome(executable_path='./chromedriver')
# chromedriver已经添加环境变量
driver = webdriver.Chrome()

# 控制浏览器访问url地址
driver.get("https://www.baidu.com/")

# 在百度搜索框中搜索'python'
driver.find_element_by_id('kw').send_keys('python')
# 点击'百度搜索'
driver.find_element_by_id('su').click()

time.sleep(6)
# 退出浏览器
driver.quit()

driver对象的常用属性和方法

在使用selenium过程中,实例化driver对象后,driver对象有一些常用的属性和方法

  1. driver.page_source 当前标签页浏览器渲染之后的网页源代码
  2. driver.current_url 当前标签页的url
  3. driver.close() 关闭当前标签页,如果只有一个标签页则关闭整个浏览器
  4. driver.quit() 关闭浏览器
  5. driver.forward() 页面前进
  6. driver.back() 页面后退
  7. driver.screen_shot(img_name) 页面截图

在selenium中可以通过多种方式来定位标签,返回标签元素对象

1
2
3
4
5
6
7
8
find_element_by_id 						(返回一个元素)
find_element(s)_by_class_name (根据类名获取元素列表)
find_element(s)_by_name (根据标签的name属性值返回包含标签对象元素的列表)
find_element(s)_by_xpath (返回一个包含元素的列表)
find_element(s)_by_link_text (根据连接文本获取元素列表)
find_element(s)_by_partial_link_text (根据链接包含的文本获取元素列表)
find_element(s)_by_tag_name (根据标签名获取元素列表)
find_element(s)_by_css_selector (根据css选择器来获取元素列表)
  • find_element和find_elements的区别:
    • 多了个s就返回列表,没有s就返回匹配到的第一个标签对象
    • find_element匹配不到就抛出异常,find_elements匹配不到就返回空列表
  • by_link_text和by_partial_link_tex的区别:全部文本和包含某个文本
  • 以上函数的使用方法
    • driver.find_element_by_id('id_str')

selenium标签页的切换

1
2
3
4
5
# 1. 获取当前所有的标签页的句柄构成的列表
current_windows = driver.window_handles

# 2. 根据标签页句柄列表索引下标进行切换
driver.switch_to.window(current_windows[0])
  • 参考代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import time
    from selenium import webdriver

    driver = webdriver.Chrome()
    driver.get("https://www.baidu.com/")

    time.sleep(1)
    driver.find_element_by_id('kw').send_keys('python')
    time.sleep(1)
    driver.find_element_by_id('su').click()
    time.sleep(1)

    # 通过执行js来新开一个标签页
    js = 'window.open("https://www.sogou.com");'
    driver.execute_script(js)
    time.sleep(1)

    # 1. 获取当前所有的窗口
    windows = driver.window_handles

    time.sleep(2)
    # 2. 根据窗口索引进行切换
    driver.switch_to.window(windows[0])
    time.sleep(2)
    driver.switch_to.window(windows[1])

    time.sleep(6)
    driver.quit()

switch_to切换frame标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import time
from selenium import webdriver

driver = webdriver.Chrome()

url = 'https://mail.qq.com/cgi-bin/loginpage'
driver.get(url)
time.sleep(2)

login_frame = driver.find_element_by_id('login_frame') # 根据id定位 frame元素
driver.switch_to.frame(login_frame) # 转向到该frame中

driver.find_element_by_xpath('//*[@id="u"]').send_keys('1596930226@qq.com')
time.sleep(2)

driver.find_element_by_xpath('//*[@id="p"]').send_keys('hahamimashicuode')
time.sleep(2)

driver.find_element_by_xpath('//*[@id="login_button"]').click()
time.sleep(2)

"""操作frame外边的元素需要切换出去"""
windows = driver.window_handles
driver.switch_to.window(windows[0])

content = driver.find_element_by_class_name('login_pictures_title').text
print(content)

driver.quit()

切换到定位的frame标签嵌套的页面中:driver.switch_to.frame(通过find_element_by函数定位的frame、iframe标签对象)

利用切换标签页的方式切出frame标签

1
2
windows = driver.window_handles
driver.switch_to.window(windows[0])

selenium对cookie的处理

获取cookie

driver.get_cookies()返回列表,其中包含的是完整的cookie信息!不光有name、value,还有domain等cookie其他维度的信息。所以如果想要把获取的cookie信息和requests模块配合使用的话,需要转换为name、value作为键值对的cookie字典

1
2
3
4
# 获取当前标签页的全部cookie信息
print(driver.get_cookies())
# 把cookie转化为字典
cookies_dict = {cookie[‘name’]: cookie[‘value’] for cookie in driver.get_cookies()}

删除cookie

1
2
3
4
5
# 删除一条cookie
driver.delete_cookie("CookieName")

# 删除所有的cookie
driver.delete_all_cookies()

selenium控制浏览器执行js代码

执行js的方法:driver.execute_script(js)

1
2
3
4
5
6
7
8
9
10
11
12
import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("http://www.baidu.com/")
time.sleep(1)

js = 'window.scrollTo(0,document.body.scrollHeight)' # js语句
driver.execute_script(js) # 执行js的方法

time.sleep(5)
driver.quit()

页面等待分类

  1. 强制等待
  2. 隐式等待
  3. 显式等待

强制等待

其实就是time.sleep()

缺点时不智能,设置的时间太短,元素还没有加载出来;设置的时间太长,则会浪费时间

隐式等待

隐式等待针对的是元素定位,隐式等待设置了一个时间,在一段时间内判断元素是否定位成功,如果完成了,就进行下一步

在设置的时间内没有定位成功,则会报超时加载

1
2
3
4
5
6
7
8
9
from selenium import webdriver

driver = webdriver.Chrome()

driver.implicitly_wait(10) # 隐式等待,最长等20秒

driver.get('https://www.baidu.com')

driver.find_element_by_xpath()

显式等待

每经过多少秒就查看一次等待条件是否达成,如果达成就停止等待,继续执行后续代码

如果没有达成就继续等待直到超过规定的时间后,报超时异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 = webdriver.Chrome()

driver.get('https://www.baidu.com')

# 显式等待
WebDriverWait(driver, 20, 0.5).until(
EC.presence_of_element_located((By.LINK_TEXT, '好123')))
# 参数20表示最长等待20秒
# 参数0.5表示0.5秒检查一次规定的标签是否存在
# EC.presence_of_element_located((By.LINK_TEXT, '好123')) 表示通过链接文本内容定位标签
# 每0.5秒一次检查,通过链接文本内容定位标签是否存在,如果存在就向下继续执行;如果不存在,直到20秒上限就抛出异常

print(driver.find_element_by_link_text('好123').get_attribute('href'))
driver.quit()

selenium开启无界面模式

绝大多数服务器是没有界面的,selenium控制谷歌浏览器也是存在无界面模式的

实例化配置对象:options = webdriver.ChromeOptions()

配置对象添加开启无界面模式的命令:options.add_argument("--headless")

配置对象添加禁用gpu的命令:options.add_argument("--disable-gpu")

实例化带有配置对象的driver对象:driver = webdriver.Chrome(chrome_options=options)

注意:macos中chrome浏览器59+版本,Linux中57+版本才能使用无界面模式

1
2
3
4
5
6
7
8
9
10
11
12
from selenium import webdriver

options = webdriver.ChromeOptions() # 创建一个配置对象
options.add_argument("--headless") # 开启无界面模式
options.add_argument("--disable-gpu") # 禁用gpu

# options.set_headles() # 无界面模式的另外一种开启方式
driver = webdriver.Chrome(chrome_options=options) # 实例化带有配置的driver对象

driver.get('http://www.baidu.com')
print(driver.title)
driver.quit()

phantomjs无界面浏览器

PhantomJS 是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript。下载地址:http://phantomjs.org/download.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from selenium import webdriver 

# 指定driver的绝对路径
driver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs')
# driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')

# 向一个url发起请求
driver.get("http://www.baidu.com/")

# 把网页保存为图片
driver.save_screenshot("1.png")

# 退出模拟浏览器
driver.quit() # 一定要退出!不退出会有残留进程!

selenium使用代理ip

实例化配置对象:options = webdriver.ChromeOptions()

配置对象添加使用代理ip的命令:options.add_argument('--proxy-server=http://202.20.16.82:9527')

实例化带有配置对象的driver对象:driver = webdriver.Chrome('./chromedriver', chrome_options=options)

  • 参考代码如下:
1
2
3
4
5
6
7
8
9
10
from selenium import webdriver

options = webdriver.ChromeOptions() # 创建一个配置对象
options.add_argument('--proxy-server=http://202.20.16.82:9527') # 使用代理ip

driver = webdriver.Chrome(chrome_options=options) # 实例化带有配置的driver对象

driver.get('http://www.baidu.com')
print(driver.title)
driver.quit()

selenium替换user-agent

实例化配置对象:options = webdriver.ChromeOptions()

配置对象添加替换UA的命令:options.add_argument('--user-agent=Mozilla/5.0 HAHA')

实例化带有配置对象的driver对象:driver = webdriver.Chrome('./chromedriver', chrome_options=options)

1
2
3
4
5
6
7
8
9
10
from selenium import webdriver

options = webdriver.ChromeOptions() # 创建一个配置对象
options.add_argument('--user-agent=Mozilla/5.0 HAHA') # 替换User-Agent

driver = webdriver.Chrome('./chromedriver', chrome_options=options)

driver.get('http://www.baidu.com')
print(driver.title)
driver.quit()

相关文章

Python基础

Python反爬解决方案

Mongodb和Python交互

Python反爬解决方案

Mongodb和Python交互

Scrapy爬虫

Scrapy爬虫