Skip to content

Latest commit

 

History

History
239 lines (160 loc) · 6.94 KB

爬虫(二).md

File metadata and controls

239 lines (160 loc) · 6.94 KB

网络爬虫(二)

动态渲染页面爬取

有的网站比如京东我们用request爬取的HTML和看到的网页不同,是因为实际的网页是通过JavaScript处理而成。

为了解决这个问题,我们可以用模拟浏览器的方式来实现爬取。

Python提供了很多模拟浏览器的库, 比如Selenuim, Splash等等。使用这些库可以完成对动态渲染页面的爬取。

Selenuim的使用

Selenuim是一个自动化测试工具,利用它可以驱动浏览器做特定的动作,比如点击,下拉等操作。同时还可以获得当前页面的源代码。

安装

pip install selenium

同时还需要安装ChromeDriver来配合使用

ChromeDriver官网选择合适自己浏览器版本的ChromeDriver安装.

基本使用

from selenium import webdriver
from selenium.webdriver.common.by import By

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")


try:
  brower.get('https://www.baidu.com')
  input = brower.find_element_by_id('kw')
  input.send_keys('Python')
  input.send_keys(Keys.ENTER)
  wait = WebDriverWait(brower, 10)
  wait.until(EC.presence_of_all_elements_located((By.ID,
                                                'content_left')))
  print(brower.current_url)
  print(brower.page_source)
finally:
  brower.close()

运行代码后会自动跳出一个浏览器,然后转到百度,输入Python并搜索,然后跳转到搜索结果页。控制台输出当前URL后,浏览器推出

除此之外page_source,会返回浏览器的真实内容,也就是可以拿到渲染之后的结果了。

详细使用

声明浏览器对象

Selenium支持很多浏览器,常见的Chrome、Edge、FireFox等

from selenium import webdriver

browser = webdriver.Chrome()
browser = webdriver.Edge()
browser = webdriver.Firefox()
browser = webdriver.Safari()

这样就完成了浏览器对象的初始化并赋值给了browser,下面要做的就是调用这个对象,让其执行各种操作。

访问页面

可以使用get()来请求页面, 参数传入链接URL即可。比如访问淘宝

brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")

brower.get("https://www.taobao.com")
print(brower.page_source)
brower.close()

运行后,浏览器会自动访问淘宝,然后输出淘宝页面的源代码,然后浏览器关闭。

查找节点

Selenium可以驱动浏览器完成各种操作,比如刚刚向输入框里面输入文字的操作。但是如何找到输入框的?Selenium提供了一系列的查找节点的方法

单个节点

比如想要从淘宝页面提取搜索框,就需要观察他的源代码

image-20210224232027270

它的id是q, name也是q。除此之外还有其他很多属性。这是就可以使用find_element_by_name()或者find_element_by_id()来选择它

brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")

brower.get("https://www.taobao.com")
input = brower.find_element_by_id('q')
print(input)
brower.close()
<selenium.webdriver.remote.webelement.WebElement (session="78c516397ce008e8697ca516d2ed2487", element="64515e6e-5fc3-439f-affb-857a90fd9d32")>

除此之外,还有函数find_element(),需要传入两个参数方式By和值, 如:

find_element(By.ID, id)

其实是上面两个函数的通用版本。

多个节点

如果想要查找的目标在网页中只有一个, 那就完全可以用find_element()方法,但是如果有多个节点,find_element()方法就只能获取第一个, 可以用要用find_elements()

节点交互

Selenium可以模拟浏览器执行一些操作,比如常见的, 输入文字send_keys(),点击按钮的click

brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")

brower.get("https://www.taobao.com")
input = brower.find_element_by_id('q')
input.send_keys('ipad')
time.sleep(1)
input.clear()
input.send_keys('iphone')
button = brower.find_element_by_class_name('btn-search')
button.click()
brower.close()

获取输入框后输入ipad,等待一秒后删掉,然后输入iphone,找到搜索按钮,然后搜索。

获取节点信息

前面的结果用page_source可以获得网页的源代码,之后就可以用解析库提取信息了。

Selenium同样提供了获取节点信息的方法

  • 获取属性 get_attribute()
  • 获取文本 text, 每个WebElement节点都有text属性,调用就可以获取文本信息
前进和后退

对于浏览器的前进后退Selenium提供了back()forward()

brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")

brower.get("https://www.taobao.com")
brower.get("https://www.baidu.com")
brower.get("https://www.python.org")
brower.back()
brower.forward()
brower.close()

爬取淘宝商品信息

# ipad
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time
from urllib.parse import quote
from pyquery import PyQuery as pq

brower = webdriver.Chrome(executable_path="/mnt/c/Users/97440/Desktop/chromedriver.exe")
wait = WebDriverWait(brower, 10)

KEYWORD = 'ipad'


def index_page(page):
  print('正在爬取第', page, '页')
  
  try:
    url = 'https://s.taobao.com/search?q=' + quote(KEYWORD)
    brower.get(url)
    
    if page > 1:
      input = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')))

      submit = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit'))
      )
      
      input.clear()
      input.send_keys(page)
      submit.click()
      
    wait.until(
      EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'),
          str(page)))
    
    wait.until(
      EC.presence_of_element_located((By.CSS_SELECTOR, '.m-itemlist .items .item')))
    get_products()
  except TimeoutException:
    index_page(page)



def get_products():
  html = brower.page_source
  doc = pq(html)
  items = doc('#mainsrp-itemlist .items .item').items()
  for item in items:
    product = {
      'image':item.find('.pic .img').attr('data-src'),
      'price':item.find('.price').text(),
      'shop':item.find('.shop').text()
    } 
    print(product)
    

MAX_PAGE = 3
def main():
  for i  in range(1, MAX_PAGE + 1):
    index_page(i)


main()