爬虫难点在哪里?
反爬问题 → 网页无法访问
页面动态信息(js脚本写入)→ 无法快速解析网页内容
页面信息js写入
网址非静态网址
selenium与requests+bs采集的异同是?
1)区别点
① 对于访问网址
selenium通过webdriver来实现,登陆则通过页面交互实现
requests实现,登陆通过设置cookies信息实现
② 对于解析网页信息
bs在解析网页标签的时候,是tag名称+属性来做定位,属于2个要素来定位
selenium则是通过1个要素定位,所以对于tag名称的需求并不是那么明显 → 掌握xpath
对于动态网页(js脚本写入),bs无法得到真实代码,selenium则可以 → 豆瓣搜索网页部分为例
2)相似点
数据采集都可以分为【网页访问】+【标签解析】
只要访问成功,页面数据采集都不是问题
未来如何搭配selenium与requests+bs?
同等情况下,requests+bs效率更高,但无法针对动态网址
搭配方案
存在【网页无法访问】与【页面动态信息】的情况下,优先用selenium解决,如果selenium和requests+bs都可以成功情况下,选择后者
实践操作:豆瓣搜索网页部分为例
案例网址:https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001 , 网页界面如下
分两部分采集
1) 1个页面获取15个书籍url链接,这里通过前10页来获取url → selenium,访问10次网址,得到150个dataurl
https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001
https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=15
https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=30
https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=45
https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=60
2) 每个书籍url链接的详细数据采集 → requests+bs,访问150次网址
步骤一、前期准备
from selenium import webdriver
import pymongo
import requests
from bs4 import BeautifulSoup
import re
import warnings
warnings.filterwarnings('ignore')
# 不发出警告
'''
1、获取书籍信息页面url
selenium
'''
urllst = ['https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001',
'https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=15',
'https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=30',
'https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=45',
'https://book.douban.com/subject_search?search_text=%E6%95%B0%E6%8D%AE&cat=1001&start=60']
# 页面网址列表
brower = webdriver.Chrome()
# 启动测试器
该部分实现相关库的导入,确定要爬取的网页网址及数量,以及启动浏览器窗口
步骤二、获取每本书的url
通过页面解析标签可知,所有的书籍内容都在【class=“item-root”】标签下面,每个数据对应的url都在【a】标签的属性【href】内部,如下
因此获取相应的信息,就可以通过下面的代码
dataurls = []
for url in urllst:
brower.get(url)
# 访问网页
divs = brower.find_elements_by_class_name('item-root')
# 获取所有包括数据的div标签
for div in divs:
url = div.find_element_by_tag_name('a').get_attribute('href')
dataurls.append(url)
# dataurl存入list
print('成功识别%i条数据网址'%len(dataurls))
print(dataurls)
运行以上的代码,输出结果如下:(这里应该是75条,第一条不是书籍的url,而是第一页的‘[丛书] 大数据技术与应用’的url)
获取每个url里面具体的信息
这里采用requests+bs获取具体的信息,第一个url需要过滤掉,代码如下
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
db = myclient['豆瓣数据采集']
datatable = db['豆瓣搜索数据爬虫']
dic_heders = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
dic_cookies = {}
cookies = 'bid=p-MBYcxHF9M; ap_v=0,6.0; gr_user_id=573d66a5-cf77-4a14-9799-8cab01e69fbc; gr_cs1_c99c8034-97a3-4160-8ed3-5490e97cdce2=user_id%3A0; _pk_ses.100001.3ac3=*; __utma=30149280.117671168.1581561701.1581561701.1581561701.1; __utmc=30149280; __utmz=30149280.1581561701.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmt_douban=1; __utma=81379588.989564917.1581561701.1581561701.1581561701.1; __utmc=81379588; __utmz=81379588.1581561701.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmt=1; _vwo_uuid_v2=D3B5A78721776CC769A182730BAA6A08D|bbbdd01c5303ea766f81b72ce3038247; __yadk_uid=AgS9pQmVaFeixgPeh4WILqM6HHzF52DK; dbcl2="150296873:ZizhwFVYPGw"; ck=t_44; gr_session_id_22c937bbd8ebd703f2d8e9445f7dfd03=1c48d36d-686f-4267-aa69-37d0bd910a4e; gr_cs1_1c48d36d-686f-4267-aa69-37d0bd910a4e=user_id%3A1; __utmb=81379588.2.10.1581561701; gr_session_id_22c937bbd8ebd703f2d8e9445f7dfd03_1c48d36d-686f-4267-aa69-37d0bd910a4e=true; push_noty_num=0; push_doumail_num=0; __utmv=30149280.15029; _pk_id.100001.3ac3=379e348ceaefb65f.1581561701.1.1581561716.1581561701.; __utmb=30149280.10.10.1581561701'
cookies_lst = cookies.split("; ")
for i in cookies_lst:
dic_cookies[i.split("=")[0]] = i.split("=")[1]
n = 1
# 设置数据库集合
errorlst = []
for u in dataurls[1:]:
try:
ri = requests.get(url = u,headers =dic_heders, cookies = dic_cookies )
soupi = BeautifulSoup(ri.text,'lxml')
# 访问并解析网址
dic = {}
dic['书名'] = soupi.h1.text.replace('\n','')
info1 = re.findall(r'[\d.]+',soupi.find('div',class_="rating_self clearfix").text)
dic['评分'] = info1[0]
dic['评价人数'] = info1[1]
# 书名、评分、评价人数匹配
info2 = soupi.find('div',id="info").text
s1 = re.sub(r' +','',info2)
lst = re.findall(r'\n.+:.+\n',s1)
for i in lst:
i = i.replace('\n','')
dic[i.split(':')[0]] = i.split(':')[1]
# 匹配简单字段
zz = re.search(r'作者:([\s\S]+)\n出版社',s1)
if zz:
dic['作者'] = zz.group(1).replace('\n','')
# 匹配作者信息,如果匹配成功则添加进字典
yz = re.search(r'译者:([\s\S]+)\n出版年',s1)
if yz:
dic['译者'] = yz.group(1).replace('\n','')
# 匹配译者信息,如果匹配成功则添加进字典
dj = re.search(r'定价:\D*([.\d]+)\D*',s1)
if dj:
dic['定价'] = dj.group(1)
# 匹配定价信息,如果匹配成功则添加进字典
#datatable.insert_one(dic) # 数据入库
print('成功采集%i条数据'%n)
n += 1
except:
print('网页采集失败,网址为:',u)
errorlst.append(u)
输出的结果为:(上面插入数据库的这条代码,如果配置好数据库的话,记得放开注释)