BeautifulSoup

基础

  1. from bs4 import BeautifulSoup
  2. from urllib.request import urlopen
  3. # if has Chinese, apply decode()
  4. html = urlopen("https://morvanzhou.github.io/static/scraping/basic-structure.html").read().decode('utf-8')
  5. print(html)
  6. soup = BeautifulSoup(html, features='lxml')
  7. print(soup.h1)
  8. """
  9. <h1>爬虫测试1</h1>
  10. """
  11. all_href = soup.find_all('a')
  12. all_href = [l['href'] for l in all_href]
  13. print('\n', all_href)
  14. # ['https://morvanzhou.github.io/', 'https://morvanzhou.github.io/tutorials/scraping']
  15. month = soup.find_all('li', {"class": "month"})
  16. for m in month:
  17. print(m.get_text())
  18. """
  19. 一月
  20. 二月
  21. 三月
  22. 四月
  23. 五月
  24. """
  25. jan = soup.find('ul', {"class": 'jan'})
  26. d_jan = jan.find_all('li') # use jan as a parent
  27. for d in d_jan:
  28. print(d.get_text())
  29. """
  30. 一月一号
  31. 一月二号
  32. 一月三号
  33. """

多功能的 Requests

  • post
    • 账号登录
    • 搜索内容
    • 上传图片
    • 上传文件
    • 往服务器传数据 等
  • get
    • 正常打开网页
    • 往服务器传数据
  1. import requests
  2. import webbrowser
  3. param = {"wd": "莫烦Python"} # 搜索的信息
  4. r = requests.get('http://www.baidu.com/s', params=param)
  5. print(r.url)
  6. webbrowser.open(r.url)
  7. # http://www.baidu.com/s?wd=%E8%8E%AB%E7%83%A6Python

Cookie

  1. payload = {'username': 'Morvan', 'password': 'password'}
  2. r = requests.post('http://pythonscraping.com/pages/cookies/welcome.php', data=payload)
  3. # post登陆之后跳转的页面
  4. print(r.cookies.get_dict())
  5. # {'username': 'Morvan', 'loggedin': '1'}
  6. r = requests.get('http://pythonscraping.com/pages/cookies/profile.php', cookies=r.cookies)
  7. # get登陆之后使用到的界面
  8. print(r.text)
  9. # Hey Morvan! Looks like you're still logged into the site!

Session

  1. session = requests.Session()
  2. payload = {'username': 'Morvan', 'password': 'password'}
  3. r = session.post('http://pythonscraping.com/pages/cookies/welcome.php', data=payload)
  4. print(r.cookies.get_dict())
  5. # {'username': 'Morvan', 'loggedin': '1'}
  6. r = session.get("http://pythonscraping.com/pages/cookies/profile.php")
  7. print(r.text)
  8. # Hey Morvan! Looks like you're still logged into the site!

下载文件

  1. import os
  2. os.makedirs('./img/', exist_ok=True)
  3. IMAGE_URL = "https://morvanzhou.github.io/static/img/description/learning_step_flowchart.png"

使用 urlretrieve

在 urllib 模块中, 提供了我们一个下载功能 urlretrieve. 使用起来很简单. 输入下载地址 IMAGE_URL 和要存放的位置. 图片就会被自动下载过去了.

  1. from urllib.request import urlretrieve
  2. urlretrieve(IMAGE_URL, './img/image1.png')

使用 request

而在 requests 模块, 也能拿来下东西. 下面的代码实现了和上面一样的功能, 但是稍微长了点. 但我们为什么要提到 requests 的下载呢? 因为使用它的另一种方法, 我们可以更加有效率的下载大文件.

  1. import requests
  2. r = requests.get(IMAGE_URL)
  3. with open('./img/image2.png', 'wb') as f:
  4. f.write(r.content)

所以说, 如果你要下载的是大文件, 比如视频等. requests 能让你下一点, 保存一点, 而不是要全部下载完才能保存去另外的地方. 这就是一个 chunk 一个 chunk 的下载. 使用 r.iter_content(chunk_size) 来控制每个 chunk 的大小, 然后在文件中写入这个 chunk 大小的数据.

  1. r = requests.get(IMAGE_URL, stream=True) # stream loading
  2. with open('./img/image3.png', 'wb') as f:
  3. for chunk in r.iter_content(chunk_size=32):
  4. f.write(chunk)

Asyncio 库

  1. import asyncio
  2. async def job(t): # async 形式的功能
  3. print('Start job ', t)
  4. await asyncio.sleep(t) # 等待 "t" 秒, 期间切换其他任务
  5. print('Job ', t, ' takes ', t, ' s')
  6. async def main(loop): # async 形式的功能
  7. tasks = [
  8. loop.create_task(job(t)) for t in range(1, 3)
  9. ] # 创建任务, 但是不执行
  10. await asyncio.wait(tasks) # 执行并等待所有任务完成
  11. t1 = time.time()
  12. loop = asyncio.get_event_loop() # 建立 loop
  13. loop.run_until_complete(main(loop)) # 执行 loop
  14. loop.close() # 关闭 loop
  15. print("Async total time : ", time.time() - t1)
  16. """
  17. Start job 1
  18. Start job 2
  19. Job 1 takes 1 s
  20. Job 2 takes 2 s
  21. Async total time : 2.001495838165283
  22. """

aiohttp

import aiohttp


async def job(session):
    response = await session.get(URL)       # 等待并切换
    return str(response.url)


async def main(loop):
    async with aiohttp.ClientSession() as session:      # 官网推荐建立 Session 的形式
        tasks = [loop.create_task(job(session)) for _ in range(2)]
        finished, unfinished = await asyncio.wait(tasks)
        all_results = [r.result() for r in finished]    # 获取所有结果
        print(all_results)

t1 = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
print("Async total time:", time.time() - t1)

"""
['https://morvanzhou.github.io/', 'https://morvanzhou.github.io/']
Async total time: 0.11447715759277344
"""

我们刚刚创建了一个 Session, 这是官网推荐的方式, 但是我觉得也可以直接用 request 形式, 细节请参考官方说明. 如果要获取网页返回的结果, 我们可以在 job() 中 return 个结果出来, 然后再在 finished, unfinished = await asyncio.wait(tasks) 收集完成的结果, 这里它会返回完成的和没完成的, 我们关心的都是完成的, 而且 await 也确实是等待都完成了才返回. 真正的结果被存放在了 result() 里面.

Selenium

如果你安装有任何的问题, 请在它们的官网上查询解决方案.

在这教你用火狐浏览器偷懒的一招, 因为暂时只有火狐上有这个插件. 插件 Katalon Recorder 下载的网址在这

Python 控制浏览器

好了, 有了这些代码, 我们就能回到 Python. 开始写 Python 的代码了. 这里十分简单! 我将 selenium 绑定到 Chrome 上 webdriver.Chrome(). 你可以绑其它的浏览器.

from selenium import webdriver

driver = webdriver.Chrome()     # 打开 Chrome 浏览器

# 将刚刚复制的帖在这
driver.get("https://morvanzhou.github.io/")
driver.find_element_by_xpath(u"//img[@alt='强化学习 (Reinforcement Learning)']").click()
driver.find_element_by_link_text("About").click()
driver.find_element_by_link_text(u"赞助").click()
driver.find_element_by_link_text(u"教程 ▾").click()
driver.find_element_by_link_text(u"数据处理 ▾").click()
driver.find_element_by_link_text(u"网页爬虫").click()

# 得到网页 html, 还能截图
html = driver.page_source       # get html
driver.get_screenshot_as_file("./img/sreenshot1.png")
driver.close()

不过每次都要看着浏览器执行这些操作, 有时候有点不方便. 我们可以让 selenium 不弹出浏览器窗口, 让它”安静”地执行操作. 在创建 driver 之前定义几个参数就能摆脱浏览器的身体了.

from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--headless")       # define headless

driver = webdriver.Chrome(chrome_options=chrome_options)
...

Scrapy

一个正常的 scrapy 项目还包括有很多其他的内容(见下面)

tutorial/
    scrapy.cfg            # deploy configuration file

    tutorial/             # project's Python module, you'll import your code from here
        __init__.py

        items.py          # project items definition file

        middlewares.py    # project middlewares file

        pipelines.py      # project pipelines file

        settings.py       # project settings file

        spiders/          # a directory where you'll later put your spiders
            __init__.py