- 前面说到用selenium爬取到TOP100,今天看了下,好像还没写完整。哭了。代码也没找到,今天写下爬取并保存到mysql数据库。
- 我在python里连接数据库时,特意查了下百度,各种搜索python连接数据库的,包括一些视频,上面大致说的是,数据库的分类,关系型数据库和非关系型数据库两种,关系型数据库最常用的就是mysql,而非关系型数据库差不多是MongodDB 这个玩意,咱也不会,咱也不敢说什么啊。
- 但是问题又来了,Python就没有mysql的接口了,现在叫pymsql,这一点别搞错了。
- 不管了,今天用mysql吧,别的以后再学。
首先是selenium的一些基本用法!
1.selenium用到的是selenium中的webdriver
from selenium import webdriver
2.webdriver提供了浏览器的启动接口
webdriver.Firefox()
3.多窗口切换
这里的多窗口是指的,多个窗口,不是一个窗口多次进入不同的网址。
通过browser.window_handles
方法得到窗口的句柄,通过browser.switch_to.window()
来切换窗口。
browser.execute_script('window.open("http://www.baidu.com")')
打开一个新的百度窗口
driver.current_url
获取当前页面的url;
driver.page_source
获取当前页面的源码;
driver.title
获取当前页面的title;
然后就是selenium中xpath的一些基本用法
1.id定位:find_element_by_id(self, id_)
2.name定位:find_element_by_name(self, name)
3.class定位:find_element_by_class_name(self, name)
4.tag定位:find_element_by_tag_name(self, name)
5.link定位:find_element_by_link_text(self, link_text)
6.partial_link定位:find_element_by_partial_link_text(self, link_text)
7.xpath定位:find_element_by_xpath(self, xpath)
8.css定位:find_element_by_css_selector(self, css_selector)
这八种是复数形式
9.id复数定位:find_elements_by_id(self, id_)
10.name复数定位:find_elements_by_name(self, name)
11.class复数定位:find_elements_by_class_name(self, name)
12.tag复数定位:find_elements_by_tag_name(self, name)
13.link复数定位:find_elements_by_link_text(self, text)
14.partial_link复数定位:find_elements_by_partial_link_text(self, link_text)
15.xpath复数定位:find_elements_by_xpath(self, xpath)
16.css复数定位:find_elements_by_css_selector(self, css_selector)
(其中element和elements一个定位是单数一个是复数)
(都是从网上找到的,嘿嘿)
然后再是scrapy的一些基本用法!
- scrapy的创建
scrapy startproject 项目名
- 爬虫的创建
进去文件里
scrapy genspider 爬虫名字 爬虫初始地址
3.scrapy里的文件
(1) item 或 items
当然创建出来是 items.py,我自己的把它改成了 item.py,因为items本身就有一个类了。
解释一下这个item.py文件是干嘛的
item是保存爬取到的数据的容器,使用方法和python中字典类似。
(2) spider爬虫文件里的一些东西
name: 用于区别spider。名字唯一。
start_urls: 爬虫爬取的url列表。 parse()方法: 是spider的方法,将每个url完成下载后生成的response对象传递给该函数。负责返回数据,提取数据。
(3) pipeline(管道)
1.process_item(self,item,spider):这是pipeline都需要调用该方法,这个方法必须返回一个具有数据的dict,或是 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理
参数:
item (Item 对象或者一个dict) – 被爬取的item
spider (Spider 对象) – 爬取该item的spider
open_spider(self,spider):当spider被开启时,被调用。
close_spider(self,spider):当spider被关闭时,被调用。
(4)middleware
下载器的中间件,就不详细介绍了,不会的可以自己百度下。
(5) settings
提供了定制scrapy组件的方法,也是选择当前激活scrapy项目的方法
然后就是代码部分了!
这是我整个scrapy文件的分布。
item.py
import scrapy
class ScrapytestItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
id = scrapy.Field()
name = scrapy.Field()
actor = scrapy.Field()
time = scrapy.Field()
from scrapy.http import HtmlResponse
from selenium import webdriver
from time import sleep
class ScrapytestDownloaderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects.
def __init__(self):
self.driver = webdriver.Firefox()
def process_request(self, request, spider):
page = int(request.meta['猫眼'])
print('!-- 正在爬取第%d页 --!'%page)
#将当前页面解析并返回
self.driver.get(request.url)
content = self.driver.page_source.encode('utf-8')
#self.driver.find_element_by_class_name('page_'+str(page+1)).click()
sleep(3)
#next_url = self.driver.current_url
return HtmlResponse(request.url,encoding='utf-8',body=content,request=request)
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
return response
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
# Must either:
# - return None: continue processing this exception
# - return a Response object: stops process_exception() chain
# - return a Request object: stops process_exception() chain
pass
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
pipelines.py(注意把自己mysql的帐号密码这个信息改下)
import pymysql
class ScrapytestPipeline(object):
def __init__(self):
# 连接数据库
config = {
'host': 'localhost'
, 'user': 'root'
, 'password': 'root'
, 'database': 'mysql'
, 'charset': 'utf8'
, 'port': 3306 # 注意端口为int 而不是str
}
self.db = pymysql.connect(**config)
print("! -- 已连接数据库 -- !")
self.cursor = self.db.cursor()
try:
c_sql = '''create table test1(
id char(3) primary key ,
name char(10) not null ,
actor char(50) not null,
time char(20) not null
);'''
self.cursor.execute("drop table if exists test1") # 如果test1表存在,就删除
self.cursor.execute(c_sql) # 加入创表
except Exception as e:
self.db.rollback()
print('Failed:', e)
def process_item(self, item, spider):
#加入数据库中
self.cursor.execute("insert into test1(id,name,actor,time)values(%s,%s,%s,%s)",(item['id'],item['name'], item['actor'], item['time']))
self.db.commit() # 统一提交
return item
def close_spider(self,spider):
self.cursor.close()
self.db.close()
settings.py(有很多没用到的,都是注释,注意下)
# -*- coding: utf-8 -*-
# Scrapy settings for scrapytest project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://doc.scrapy.org/en/latest/topics/settings.html
# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'scrapytest'
SPIDER_MODULES = ['scrapytest.spiders']
NEWSPIDER_MODULE = 'scrapytest.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'scrapytest (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
#COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0',
}
# Enable or disable spider middlewares
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
# 'scrapytest.middlewares.ScrapytestSpiderMiddleware': 543,
#}
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
'scrapytest.middlewares.ScrapytestDownloaderMiddleware': 543,
}
# Enable or disable extensions
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
# 'scrapytest.pipelines.ScrapytestPipeline': 300,
#}
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
ITEM_PIPELINES = {'scrapytest.pipelines.ScrapytestPipeline' : 100}
爬虫部分test1(我的爬虫名就这个,都是自己取的)
from scrapy import Spider,Request
import re
import sys
sys.path.append('E:\python爬虫\scrapytest\scrapytest')
from item import ScrapytestItem
class test1Spider(Spider):
name = "test1"
def start_requests(self):
self.url = 'https://maoyan.com/board/4'
self.meta = {'猫眼': 1}
self.num = 1
yield Request(url=self.url, callback=self.parse, meta=self.meta)
def parse(self, response):
movies = response.xpath('//div[@class="movie-item-info"]')
self.meta['猫眼']+=1
try:
response.xpath('//a[@class="page_%d"]/@href'%self.meta['猫眼'])
next_url = response.xpath('//a[@class="page_%d"]/@href'%self.meta['猫眼']).extract()
except:
print('<-- 页数已经到底了! -->')
else:
print('<-- 页数存在 -->')
#通过item.py文件里的类定义的一个item
item = ScrapytestItem()
#通过得到返回的网页利用xpath得到name,actor,time
for movie in movies:
id = str(self.num)
self.num+=1
name = movie.xpath('.//p[@class="name"]/a/text()').extract()
actor = movie.xpath('.//p[@class="star"]/text()').extract()
actor[0] = str(actor[0])
actor[0] = re.sub("[\n 主演:]","",actor[0])
time = movie.xpath('.//p[@class="releasetime"]/text()').extract()
time[0] = str(time[0])
time[0] = re.sub('[\n 上映时间:]', '',time[0])
item['id'] = id
item['name'] = name
item['actor'] = actor
item['time'] = time
yield item
try:
next_url= self.url+next_url[0]
while True:
yield Request(meta=self.meta, callback=self.parse, url=next_url)
except:
print('<-- 已经是最后一页了! -->')
#关闭爬虫
self.crawler.engine.close_spider(self,"<-- 已经爬取完毕! -->")
- 接下来就是启动爬虫了,可以在命令行进入自己scrapy的根目录下,scrapy crawl 爬虫名 (我的爬虫名就是test1)
我感觉这个不太方便,我是在和scrapy.cfg这个目录下,新建了一个main.py文件,代码如下:
from scrapy.cmdline import execute
import sys
import os
sys.path.append(os.path.dirname(__file__))
execute(["scrapy","crawl","test1"])
这个看着改吧。
- selectors选择器(通过这个选择器来提取数据。)
.xpath() :传入xpath表达式
.css():传入css表达式
extract():序列化该节点为unicode字符串并返回list
re():传入正则表达式 - 然后就是test1.py文件中Request的参数:
url: 就是需要请求,并进行下一步处理的url
callback: 指定该请求返回的Response,由哪个函数来处理
method: 一般不需要指定,使用默认GET方法请求即可
headers: 请求时,包含的头文件。一般不需要
meta: 比较常用,在不同的请求之间传递数据使用的
encoding: 使用默认的 ‘utf-8’ 就行
errback: 指定错误处理函数
dont-filter: 默认参数为false,检查重复url的 - middlewares.py中的参数response参数:
由于response是不能直接调用的,所以用它的子类Htmlresponse不过参数都是差不多的吧(别的没用过)。
url(string) - 此响应的URL
status(integer) - 响应的HTTP状态。默认为200
headers(dict) - 这个响应的头。dict值可以是字符串或列表
body(str) - 响应体
flags(list) - 是一个包含属性初始值的 Response.flags列表
request(Requestobject) - 属性的初始值Response.request - 最后总结一下吧,这个总的来说完成了爬取到保存,虽然不是在数据库里面不是按1到100的顺序来排的,不过也凑合吧,非要按顺序,就最后加一条数据库按顺序排的那个sql语句就可以了。整个这个花了我差不多2个多星期吧,虽然一般一天就3 4个小时,有时候还有别的事,不过总算是会用一点点scrapy框架了,嘿嘿。确实比自己写整个爬虫要方便的多,不过也特别的难懂吧,scrapy里的大多数还没弄懂,不过再慢慢来吧,还是比较有收获的了。
- 再来说下有关爬虫翻页的这个问题吧,确实我在网上找了特别多篇用scrapy+selenium翻页的问题,不过是没有不会那种自动爬取完,自动点击网页中的下一页爬取这样的,我试了特别多方法,比如用Htmlresponse返回下一个的网址,然后再yield这个新的url,不过也不行,不知道是不是我自己菜的问题,然后我这个就是用的通过爬取的这个网页的下一页这个标签里里找到下一页的那个网址的后面的那个尾巴 ,加上网址TOP首页就是下一页的网址,把这个url传回middlewares就是下一页了,如果还有别的方法的话可以交流下,我自己也会慢慢探索的。
- 然后就是为什么用的是猫眼电影的这个网站爬取,因为这个爬取可以不用登陆,像爬取淘宝的那些商品信息就要登陆了,本来就是刚学scrapy,还是搞个简单点的吧。嘿嘿。
差不多就这些了,这么些天自己专研出来的,可能有点繁琐,希望有用吧。