部分网站是动态js加载,加载网页后无法找到实际抓取内容。如今日头条等,反爬比较厉害,api不好破解的情况下只能通过浏览器模拟渲染加载方式,不过selenium等驱动浏览器很有一定标识和指纹,很容易被识别。selenium浏览器driver 源码中某个变量名是表示该驱动特征的,变量名会被识别,一般办法是改变变量名称或者拦截包含该变量名的请求就行了,拦截需要中间件。由于修改太繁琐,网上也有编译好的Chromedriver,特征已经被抹除,这样就不会被今日头条,知乎识别到。暂时发现Scrapy Splash识别不到,可以正常加载爬取。
1.可以基于selenium webdriver,Chrome,Firefox, PhantomJS无界面浏览器加载。selenium中文文档: https://python-selenium-zh.readthedocs.io/zh_CN/latest/7.WebDriver%20API/
2.可以使用 splinter 加载,Splinter 是用 Python 开发的一个开源web自动化测试的工具集。 它可以帮你自动化浏览器的行为,比如浏览 URLs 并和页面进行交互。类似selenium,常规网站操作交互都有。splinter官方文档: https://splinter-docs-zh-cn.readthedocs.io/zh/latest/
如:
from splinter import Browser
import time
url = "http://baidu.com"
# browser = Browser('chrome', headless=True)
browser = Browser('chrome')
browser.visit(url)
# 找到并点击搜索按钮
button = browser.find_by_xpath('//input[@type="submit"]')
# 与元素交互
button.click()
print(browser.html)
time.sleep(30)
3.Scrapy Splash 用来爬取动态网页,其效果和scrapy selenium phantomjs一样,Scrapy Splash是lua脚本写的一个js渲染服务,通过渲染js得到动态网页然后实现网页解析,Splash是官推的js渲染引擎,和Scrapy结合比较好,使用的是webkit开发的轻量级无界面浏览器,渲染之后结果和静态爬取一样可以直接用xpath处理。只是splash是在docker中运行。Scrapy Splash官方文档:https://splash-cn-doc.readthedocs.io/zh_CN/latest/scrapy-splash-toturial.html
代码示例:
settings文件设置
import scrapy
import time
import requests
import json
from qctt.items import toutiaoAuthorItem
import os
from qctt.sqlManager import MySQLManager
import random
from scrapy_splash import SplashRequest
from scrapy.crawler import CrawlerProcess
from qctt.settings import *
from qctt.Utils import *
script1 = """
function main(splash, args)
splash:go(args.url)
local scroll_to = splash:jsfunc("window.scrollTo")
scroll_to(0, 5000)
splash:set_viewport_full()
return {png=splash:png()}
end
"""
class ToutiaoNewsSpider(scrapy.Spider):
name = 'toutiaoNews'
def start_requests(self):
urls=["https://www.toutiao.com/c/user/3434439868/#mid=3443995426",
"https://www.toutiao.com/c/user/4280517202/#mid=4280698022",
"https://www.toutiao.com/c/user/6263094546/#mid=6260524942"]
for url in urls:
meta={'author':"test"}
yield SplashRequest(url=url,
callback=self.parseNewsList,
args={'wait': 1},
endpoint='render.html',
meta=meta
)
#解析搜索结果
def parseNewsList(self, response):
# print(response.text)
lis = response.xpath('*//div[@class="relatedFeed"]/ul/li')
# print(lis)
mediaName =response.meta['author']
for li in lis:
try:
title = li.xpath(
'.//div[@class="title-box"]/a/text()').extract_first()
href = li.xpath(
'.//div[@class="title-box"]/a/@href').extract_first()
readCount = li.xpath(
'.//div[@class="y-left"]/a[@class="lbtn"]/text()').extract_first()
commentCount = li.xpath(
'.//div[@class="y-left"]/a[@class="lbtn comment"]/text()').extract_first()
publishTime = li.xpath(
'.//div[@class="y-left"]/span/text()').extract_first()
publishTime = publishTime.replace('⋅ ', '')
newsids = href.split('/')
newsid = newsids[2]
newsurl = 'https://www.toutiao.com/i' + newsid
print(title)
print(href)
print(readCount)
print(publishTime)
print(commentCount)
print(newsurl)
except Exception as e:
print(e)
#从url解析用户id和媒体id
def getuserIdAndmediaId(sefl,url):
info = url.split('&user_id=')[1]
userId = info.split('&')[0]
mediaInfo = info.split('&')[-1]
mediaId = mediaInfo.split('media_id=')[1]
# print(userId,mediaId)
return userId,mediaId
#函数主入口,测试使用
if __name__ == "__main__":
process = CrawlerProcess({'USER_AGENT':'Mozilla/4.0(compatible;MSIE7.0;WindowsNT5.1)'})
process.crawl(ToutiaoNewsSpider)
process.start()
有问题可以评论区留言交流。