多线程爬虫
- 使用流程
# 1、URL队列
q.put(url)
# 2、线程事件函数
while True:
if not url_queue.empty():
...get()、请求、解析
else:
break
# 创建并启动线程
t_list = []
for i in range(5):
t = Thread(target=parse_page)
t_list.append(t)
t.start()
# 阻塞等待回收线程
for i in t_list:
i.join()
json模块
- json转python
变量名 = json.loads(res.text))
- python转json(保存为json文件)
# 保存所抓取数据为json数据
with open(filename,'a') as f:
json.dump(字典/列表/元组,f,ensure_ascii=False)
selenium+phantomjs/chrome/firefox
- 特点
1、简单,无需去详细抓取分析网络数据包,使用真实浏览器
2、需要等待页面元素加载,需要时间,效率低
- 使用流程
from selenium import webdriver
# 创建浏览器对象
browser = webdriver.Firefox()
browser.get('https://www.jd.com/')
# 查找节点
node = browser.find_element_by_xpath('')
node.send_keys('')
node.click()
# 获取节点文本内容
content = node.text
# 关闭浏览器
browser.quit()
- 设置无界面模式(chromedriver | firefox)
options = webdriver.ChromeOptions()
options.add_argument('--headless')
browser = webdriver.Chrome(options=options)
browser.get(url)
京东爬虫
- 执行JS脚本,把进度条拉到最下面
1、js脚本
browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
2、利用节点对象的text属性获取当前节点及后代节点的文本内容,想办法处理数据
scrapy框架
- 五大组件
引擎(Engine)
爬虫程序(Spider)
调度器(Scheduler)
下载器(Downloader)
管道文件(Pipeline)
# 两个中间件
下载器中间件(Downloader Middlewares)
蜘蛛中间件(Spider Middlewares)
- 工作流程
1、Engine向Spider索要URL,交给Scheduler入队列
2、Scheduler处理后出队列,通过Downloader Middlewares交给Downloader去下载
3、Downloader得到响应后,通过Spider Middlewares交给Spider
4、Spider数据提取:
1、数据交给Pipeline处理
2、需要跟进URL,继续交给Scheduler入队列,依次循环
- 常用命令
# 创建爬虫项目
scrapy startproject 项目名
# 创建爬虫文件
cd 项目文件夹
scrapy genspider 爬虫名 域名
# 运行爬虫
scrapy crawl 爬虫名
- scrapy项目目录结构
Baidu
├── Baidu # 项目目录
│ ├── items.py # 定义数据结构
│ ├── middlewares.py # 中间件
│ ├── pipelines.py # 数据处理
│ ├── settings.py # 全局配置
│ └── spiders
│ ├── baidu.py # 爬虫文件
└── scrapy.cfg # 项目基本配置文件
- settings.py全局配置
1、USER_AGENT = 'Mozilla/5.0'
# 是否遵循机器人协议
2、ROBOTSTXT_OBEY = False
# 最大并发数
3、CONCURRENT_REQUESTS = 32
4、DOWNLOAD_DELAY = 1
5、DEFAULT_REQUEST_HEADERS={
}
6、ITEM_PIPELINES={
'项目目录名.pipelines.类名':300}
Day07笔记
selenium补充
切换页面
1、适用网站
页面中点开链接出现新的页面,但是浏览器对象browser还是之前页面的对象(url未变)
2、应对方案
# 获取当前所有句柄(窗口)
all_handles = browser.window_handles
# 切换到新的窗口
browser.switch_to_window(all_handles[1])
3、民政部网站案例
3.1 目标: 将民政区划代码爬取到数据库中,按照层级关系(分表 – 省表、市表、县表)
3.2 数据库中建表
# 建库
create database govdb charset utf8;
use govdb;
# 建表
create table province(
p_name varchar(20),
p_code varchar(20)
)charset=utf8;
create table city(
c_name varchar(20),
c_code varchar(20),
c_father_code varchar(20)
)charset=utf8;
create table county(
x_name varchar(20),
x_code varchar(20),
x_father_code varchar(20)
)charset=utf8;
3.3 思路
1、selenium+Chrome打开一级页面,并提取二级页面最新链接
2、增量爬取: 和数据库version表中进行比对,确定之前是否爬过(是否有更新)
3、如果没有更新,直接提示用户,无须继续爬取
4、如果有更新,则删除之前表中数据,重新爬取并插入数据库表
5、最终完成后: 断开数据库连接,关闭浏览器
3.4 代码实现
from selenium import webdriver
import time
import pymysql
class GovementSpider(object):
def __init__(self):
# 创建浏览器对象 + 打开一级页面
self.options = webdriver.ChromeOptions()
self.options.add_argument('--headless')
self.browser = webdriver.Chrome(options=self.options)
self.one_url = 'http://www.mca.gov.cn/article/sj/xzqh/2019/'
# 数据库相关变量
self.db = pymysql.connect('192.168.153.134', 'tiger', '123456', 'govdb', charset='utf8')
self.cursor = self.db.cursor()
# 定义数据库中三张表的列表,后续使用executemany方法将数据插入数据库
self.province_list = []
self.city_list = []
self.county_list = []
# 获取首页,并提取最新二级页面链接
def get_two_url(self):
self.browser.get(self.one_url)
# 提取最新二级页面链接节点 + 点击该节点
td_list = self.browser.find_elements_by_xpath('//td[@class="arlisttd"]/a[contains(@title,"中华人民共和国县以上行政区划代码")]')
if td_list:
two_url_element = td_list[0]
# 增量爬取数据库核对
two_url = two_url_element.get_attribute('href')
sel = 'select * from version'
self.cursor.execute(sel)
result = self.cursor.fetchall()
if result:
version_url = result[-1][0]
else:
version_url = ''
# 和数据库中url做比对
if two_url == version_url:
print('已是最新,无需爬取')
else:
two_url_element.click()
# 获取当前所有句柄 + 将browser切换到新的页面
all_handles = self.browser.window_handles
self.browser