环境配置
import requests
from bs4 import BeautifulSoup
import time
import lxml
import re
import os
from threading import Thread
from multiprocessing import Process
import json
有些不是必须的,有些可以换成别的使用,这里讲最简单,那就是requests
确认URL
在爬取一个网页的信息前,首先在明确这个网页的url,也就是链接,这是前提,我们的工作都是围绕这个url进行的,其实就是确认网址这个工作。
发送请求
发送请求,也就是让代码执行我们访问网页的一些动作,这就要求我们提供发送请求必要的一些东西,比如请求的header,根据修改请求的信息,我们可以根据目的访问移动端网页或者访问PC端网页。下面以PC端为例:
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/69.0.3486.0 Safari/537.36'}
有了这个header后,我们调用requests库的get函数,传入url以及header两个参数,这样即可轻松得到对应url下的信息。
response = requests.get(url=url, headers=header)
response.encoding = 'utf-8' #编一下码
响应信息的处理
这是最核心的步骤,需要做的工作有很多,也有各种工具可以处理,最常用的应该是BeautifulSoup库。soup库的很多用法和函数,网上资料很多,这里讲最常用的。
soup = BeautifulSoup(response.text, 'lxml') #将请求回馈的信息载入soup对象中
[soup.extract() for soup in soup('script')] #去除script脚本信息干扰
[soup.extract() for soup in soup('style')] #去除style信息干扰
title = soup.find('h1').text #将网页中h1标签中的内容赋予title变量
cont = soup.find(id = 'artibody') #将id为artibody中的内容赋予cont变量
#title和cont都是str对象,是可以进一步使用字符串处理的
相信到这里,很多人都已经能爬一些最简单的东西的,但是,有些人可能连html标签都不清楚,这怎么办?很简单,网页F12一打开,用好F12就好了,使用F12跳出的页面左上角那个箭头图标,你能轻易找到对应信息的标签信息。然后查一下soup就知道怎么搞了。
这其实还不够,你可能遇到标签信息难以定位的元素,怎么办?这种情况可能比较麻烦,但其实也不难,直接使用正则re库对 request.text 整html个文档进行字符串匹配也是能做到的。
进阶——动态网页的爬取
上面几步,基本上已经解决了绝大多数简单的问题,但随着web技术不断发展,好爬的网站不多了。很多网站用的都是动态网页,或者信息要加载后才能爬取,这该怎么办?这里提供两种方法:
1. 模拟浏览器访问
这里需要用到webdriver,也就是selenium的东西,因为速度较慢,不推荐。环境:from selenium import webdriver
一般,我们都是用无头浏览器,也就是不显示页面以加快速度:
option = webdriver.ChromeOptions()
option.add_argument('headless')
driver = webdriver.Chrome(chrome_options = option)
这里用到是google,其他浏览器也可以,但是要selenium能用的才行,网上有更详细的配置方法,这里只是提供思路。有了它之后,调用它的get方法,就能得到之前得不到的信息。如下面的例子,获取b站视频播放量(很墨迹的做法,仅仅只是提供参考,顺便学习一下正则的用法)。
driver.get('https://www.bilibili.com/video/av39738835')
time.sleep(10)
html = driver.find_element_by_xpath("//*").get_attribute("outerHTML")
soup = BeautifulSoup(html,'html.parser')
matcher1 = soup.select('h1')
matcher2 = soup.find('span', class_="view")
regex = r'title=\"([\s\S]*?)\"'
matches1 = re.findall(regex, str(matcher1))
matches2 = re.findall(regex, str(matcher2))
print("名称:",matches1)
print("播放量:",matches2)
2. 根据具体请求获取动态信息
这个是最好的做法,要知道,网页信息既然能显示在我们电脑上,就说明我们是完全有能力靠代码获取这些信息的。只要发送响应请求即可,同样以B站视频为例子。用F12打开页面,点击Network一栏,注意电脑发送的请求,此时应该是空白状态,刷新一下网页,看看电脑发送了哪些请求。此时请求必然很多。
但是注意原则寻找对应信息还是不难的,现在一般都是json传输这种简单的数据。看请求名字其实也能猜出哪个是你想要的。比如B站对应视频的播放量,肯定是和av号挂钩的,根据这个我们就轻松找到这个js回应了。爬多了,这些还是很好找的。接着,利用json库处理数据。找到想要的信息对应的键值,这里可以通过json的官网帮助解析。下面是代码:
url = 'https://api.bilibili.com/x/web-interface/view?aid=39738835&cid=69811683'
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/69.0.3486.0 Safari/537.36'}
response = requests.get(url=url, headers=header)
response.encoding = 'utf-8'
result2 = json.loads(response.text)['data']['stat']['view']
result1 = json.loads(response.text)['data']['title']
print('title : ', result1,'\n播放量 : ', result2)
相信你能很轻松地掌握json文件的结构,也能明白动态网页信息的获取。
加速——多线程爬取
由于网页信息爬取是一项重复性的工作,且爬取不同网页间基本是不存在交互的,因此,我们完全可以使用多线程来完成我们的任务。首先是环境,只需要多加threading库和multiprocessing库即可。
环境:
from threading import Thread
from multiprocessing import Process
代码示例:
def myfun(i):
print(i)
if __name__ == '__main__':
threads = []
print("CPU: ", os.cpu_count())
for i in range(1,31):
thread = Process(target=myfun, args=(i, ))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
根据上面的多线程运作函数样例,想必你能轻松地将之应用到爬取多个网页信息上。