答:
python:代码简洁,开发效率高,第三方模块多,相关的HTTP请求模块HTML解析模块非常丰富,拥有强大的爬虫框架scrapy以及成熟高效的scrapy-redis分布式策略,调用其他接口非常方便(胶水语言)
PHP:对多线程异步支持不够好,处理并发能力弱,爬虫是工具性程序,对速度、效率要求很高
Java:网络爬虫生态圈很完善,是python爬虫的最大对手。但是缺点是Java语言本身很笨重,代码量很大,任何修改都会导致代码的大量改动,而爬虫经常会因为网站的修改而修改采集代码
C/C++:运行效率和性能 很强,但是学习成本太高,代码成型比较慢
HTTP请求的处理,urllib,urllib2,requests
处理后的请求可以模拟浏览器,获取服务器响应的文件
使用某种面属性语言来给需要提取的数据,定义一个匹配规则,符合这个规则的数据就会被匹配
re、xpath、beautifulSoup、jsonpath、pyquery等
动态页面采集:Selenium自动化测试工具+chromedriver模拟浏览器行为获取数据;模拟真实浏览器加载js、ajax等非静态页面采集
使用selenium关闭浏览器:
selenium定位元素:
selenium表单操作:
from selenium.webdriver.support.ui import Select
来包装一下选中的对象,才能进行select
选择:
inputTag = driver.find_element_by_id('kw')
submitTag = driver.find_element_by_id('su')
actions = ActionChains(driver)
actions.move_to_element(inputTag)
actions.send_keys_to_element(inputTag,'python')
actions.move_to_element(submitTag)
actions.click(submitTag)
actions.perform()
更多的鼠标相关的操作。
click_and_hold(element):点击但不松开鼠标。
context_click(element):右键点击。
double_click(element):双击。
获取所有的cookie:
for cookie in driver.get_cookies():
print(cookie)
根据cookie的key获取value:
value = driver.get_cookie(key)
删除所有的cookie:
driver.delete_all_cookies()
删除某个cookie:
driver.delete_cookie(key)
添加cookie:
driver.add_cookie({“name”:”username”,”value”:”abc”})
隐式等待:指定一个时间,在这个时间内一直会处于等待状态。隐式等待需要使用driver.implicitly_wait
。
显式等待:指定在某个时间内,如果某个条件满足了,那么就不会再等待,如果在指定的时间内条件都不满足,那么就不会再等待了。显式等待用的方法是from selenium.webdriver.support.ui import WebDriverWait
。示例代码如下:
driver.get("https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc")
WebDriverWait(driver,100).until(
EC.text_to_be_present_in_element_value((By.ID,"fromStationText"),"长沙")
)
WebDriverWait(driver,100).until(
EC.text_to_be_present_in_element_value((By.ID,"toStationText"),"北京")
)
btn = driver.find_element_by_id("query_ticket")
btn.click()
selenium中没有专门的打开新窗口的方法,是通过window.execute_script()
来执行js
脚本的形式来打开新窗口的。
window.execute_script("window.open('https://www.douban.com/')")
打开新的窗口后driver
当前的页面依然还是之前的,如果想要获取新的窗口的源代码,那么就必须先切换过去。示例代码如下:
window.switch_to.window(driver.window_handlers[1])
tesseract:机器学习库,机器学习图像识别系统,处理简单的验证码
复杂验证码可以手动输入或者找专门的打码平台
高定制性、高性能(异步网络框架twitsted),所以数据下载速度非常快,高并发,提供了数据存储、数据下载、提取规则等组件
pip install scrapy
middlewares.py
:用来定义中间件。items.py
:用来提前定义好需要下载的数据字段。pipelines.py
:用来保存数据。scrapy.cfg
:用来配置项目的def __init__(self,mysql_config):
self.dbpool = adbapi.ConnectionPool(
mysql_config['DRIVER'],
host=mysql_config['HOST'],
port=mysql_config['PORT'],
user=mysql_config['USER'],
password=mysql_config['PASSWORD'],
db=mysql_config['DATABASE'],
charset='utf8'
)
@classmethod
def from_crawler(cls,crawler):
# 只要重写了from_crawler方法,那么以后创建对象的时候,就会调用这个方法来获取pipline对象
mysql_config = crawler.settings['MYSQL_CONFIG']
return cls(mysql_config)
runInteraction
来运行真正执行sql语句的函数。示例代码如下:def process_item(self, item, spider):
# runInteraction中除了传运行sql的函数,还可以传递参数给回调函数使用
result = self.dbpool.runInteraction(self.insert_item,item)
# 如果出现了错误,会执行self.insert_error函数
result.addErrback(self.insert_error)
return item
def insert_item(self,cursor,item):
sql = "insert into article(id,title,author,pub_time,content,origin) values(null,%s,%s,%s,%s,%s)"
args = (item['title'],item['author'],item['pub_time'],item['content'],item['origin'])
cursor.execute(sql,args)
def insert_error(self,failure):
print("="*30)
print(failure)
print("="*30)
下载器中间件是引擎和下载器之间通信的中间件。在这个中间件中我们可以设置代理、更换请求头等来达到反反爬虫的目的。要写下载器中间件,可以在下载器中实现两个方法。一个是process_request(self,request,spider),这个方法是在请求发送之前会执行,还有一个是process_response(self,request,response,spider),这个方法是数据下载到引擎之前执行。
设置普通代理:
class IPProxyDownloadMiddleware(object):
PROXIES = [
"5.196.189.50:8080",
]
def process_request(self,request,spider):
proxy = random.choice(self.PROXIES)
print('被选中的代理:%s' % proxy)
request.meta['proxy'] = "http://" + proxy
设置独享代理:
class IPProxyDownloadMiddleware(object):
def process_request(self,request,spider):
proxy = '121.199.6.124:16816'
user_password = "970138074:rcdj35xx"
request.meta['proxy'] = proxy
# bytes
b64_user_password = base64.b64encode(user_password.encode('utf-8'))
request.headers['Proxy-Authorization'] = 'Basic ' + b64_user_password.decode('utf-8')
scrapy-redis,在scrapy基础上添加了一套以redis数据库为核心的组件,让scrapy框架支持分布式的功能,主要在redis里做请求去重、请求分配、数据临时存储等
在ubuntu上安装redis:sudo apt install redis-server
连接reids服务器:redis-cli -h [ip地址] -p [端口号]
在其他电脑上连接本机的redis服务器:在/etc/redis/redis.conf中,修改bind,把redis服务器的ip地址加进去。示例如下:
bind 192.168.175.129 127.0.0.1
vim:有可能没有。那么通过sudo apt install vim就可以安装了。
虚拟机安装:vmware+ubuntu16.04.iso来安装。安装的时候,设置root用户的密码,用useradd
命令来创建一个普通用户。后期方便通过xshell来连接。ubuntu不允许外面直接用root用户链接,那么我们可以先用普通用户连接,然后再切换到root用户
在服务器上安装scrapyd:pip3 install scrapyd
。
从/usr/local/lib/python3.5/dist-packages/scrapyd
下拷贝出default_scrapyd.conf
放到/etc/scrapyd/scrapyd.conf
。
修改/etc/scrapyd/scrapyd.conf
中的bind_address
为自己的IP地址。
重新安装twisted
:
pip uninstall twisted
pip install twisted==18.9.0
如果这一步不做,后期会出现intxxx的错误。
在开发机上(自己的window电脑上)安装pip install scrapyd-client
。
修改python/Script/scrapyd-deploy
为scrapyd-deploy.py
在项目中,找到scrapy.cfg
,然后配置如下:
[settings]
default = lianjia.settings
[deploy]
# 下面这个url要取消注释
url = http://服务器的IP地址:6800/
project = lianjia
在项目所在的路径执行命令生成版本号并上传爬虫代码:scrapyd-deploy
。如果一次性想要把代码上传到多个服务器,那么可以修改scrapy.cfg
为如下:
[settings]
default = lianjia.settings
[deploy:服务器1]
# 下面这个url要取消注释
url = http://服务器1的IP地址:6800/
project = lianjia
[deploy:服务器2]
# 下面这个url要取消注释
url = http://服务器2的IP地址:6800/
project = lianjia
然后使用scrapyd-deploy -a
就可以全部上传了。
curl for windows下载地址:https://curl.haxx.se/windows/
,解压后双击打开bin/curl.exe即可在cmd中使用了。
在cmd中使用命令运行爬虫:
curl http://服务器IP地址:6800/schedule.json -d project=lianjia -d spider=house
如果后期修改了爬虫的代码,那么需要重新部署,然后服务器的scrapyd服务重新启动一下。
user-agent、代理、、验证码、动态页面加载、加密数据
HTTP协议:超文本传输协议,是一种发布和接收HTML页面的方法,端口:80
HTTPS协议:HTTP的安全版,在HTTP下价SSL层。端口:443
SSL层(安全套接层):主要用于web的安全传输协议,在传输层对网络连接进行加密,保障在Internet上数据传输安全。
网络爬虫抓取过程:模拟浏览器操作的过程
浏览器主要功能是向服务器发出请求,在浏览器窗口中展示你选择的网络资源,HTTP是一套计算机通过网络进行通信的规则。
HTTP通信:客户端请求信息、服务器响应信息
浏览器发送HTTP请求的过程:
Get:请求的URL会附带参数
Post:请求的URL不会带参数
对于Get请求:查询参数在QueryString里保存
对于Post请求:查询参数在Form表单中保存,通常会用一个换行进行分割
scheme://host[:port#]/path/…/?query-string
scheme:协议
host:服务器的ip地址或者域名
port#:服务器的端口
path:访问资源的路径
query-string:参数,发送给HTTP夫妻的数据
anchor:锚,跳转到网页的指定锚点位置
请求行、请求头、空行、请求数据
Get:从服务器上获取数据;请求参数显示在URL地址上
Post:从服务器获取数据的同时,向服务器传送数据
cookie:通过在客户端记录的信息确认用户的身份
session:通过在服务器端记录的信息确认用户的身份
import urllib.parse
urlencode() # 转码,接收的是字典
unquote() # 解码
import urllib.request
url = 'http://www.baidu.com/s'
headers = {'User-Agenturlencode()': 'Mozilla...'}
keyword = input('请输入需要查询的字符串')
wd = {'wd': keyword}
# 通过urllib.parse.urlencode() 参数是一个dict类型
wd = urllib.parse.urlencode(wd)
# 拼接完整的url字符串
fullurl = url + '?' + wd
# 构造请求对象
request = urllib.request.Request(fullurl, headers=headers)
response = urllib.request.urlopen(request)
西刺免费代理IP https://www.xicidaili.com/
快代理 https://www.kuaidaili.com/free/inha/
IP海 http://www.iphai.com/free/ng
代理的使用:{代理类型,ip与端口}
{‘HTTP’: ‘218.241.219.226:9999’}
将代理IP放在系统环境变量中:cd ~/.bash_profile中
加入:
proxyuser = '用户名'
export proxyuser
proxypassword = '密码'
export proxypassword
在命令行窗口,输入source ~/.bash_profile,使系统环境变量生效
在自己的代码中:
import os
proxyuser = os.environ.get('proxyuesr')
proxypassword = os.environ.get('proxypassword')
将用户名和密码与ip拼接起来
python中的re模块游两种方式:
pattern = re.compile(’\d’)将正则表达式编译成一个pattern规则对象
m = pattern.match()从开始位置查找,找到第一个就返回,值匹配一次
pattern.search()从任何位置查找,找到第一个就返回,只匹配一次
pattern.findall()所有的全部匹配,返回列表
pattern.finditer()所有的全匹配,返回的是一个迭代器
pattern.split()分割字符串,返回列表
pattern.sub()替换
m.group()取出匹配的内容
re.I 表示忽略大小写
re.S 表示全文匹配
XML:可扩展标记语言,被设计为传输和存储数据,其焦点是数据的内容
HTML:超文本标记语言,显示数据以及如何更好的显示数据
HTML DOM:文档对象模型,通过HTML DOM,可以访问所有的HTML元素,联通他们所包含的文本和属性,可以对其中的内容进行修改和删除,也可以创建新的元素
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
四大对象种类:Tag、NavigableString、BeautifulSoup、Comment
1)Tag:标签
soup.title
soup.head
2)NavigableString:获取标签内部的文字 .string
soup.p.string
3)BeautifulSoup:文档的内容,相当于特殊的Tag
4)Comment:特殊类型的 NavigableString 对象,输出内容没有注释的内容
JSON:JavaScript中的对象和数组。对象{},数组[]
import json
json.loads() # 将json格式转换为python格式
json.dumps() # 将python类型转化为json字符串,返回一个str对象
json.dump() # 将python内置类型序列化为json后写入文件
json.load() # 将json类型序列化为python后写入文件