在fritzing中插入自己的丝印图像

一直以来,fritzing很受欢迎,但因其用户绝大多数为非行业用户,深入应用案例较少,如何在fritzing的PCB中使用自己的logo或文字网上资料很少,这里给出一个比较简单的方法。

1、安装LibreOffice软件,该软件是流行的免费开源办公软件,对标微软办公三件套

2、打开LibreOffice Draw程序,新建文件并插入艺术字,字体和形状根据自己需要修改

3、修改页面属性中的页面大小,适配艺术字长宽大小

4、导出文件格式为svg

5、在fritzing的PCB视图中插入silkscreen image

树莓派中nohup 、&、重定向的使用

一、nohup 和 & 使用方法

1.1、 nohup (不挂断)

nohup 是 no hung up 的缩写,意思是不挂断 。
使用 Xshell 等Linux 客户端工具,远程执行 Linux 脚本时,有时候会由于网络问题,导致客户端失去连接,终端断开,脚本运行一半就意外结束了。这种时候,就可以用nohup 指令来运行指令,使脚本可以忽略挂起,仍可继续运行。
nohup 语法格式:

nohup command [arg…]
1
说明:

除了无法进行输入操作(比如输入命令、换行、打空格等) 外 ,
标准输出 保存到 nohup.out文件中。
关闭客户端后,命令仍然会运行,不会挂断。
例如:

执行 nohup sh test.sh 脚本命令后,终端不能接收任何输入,标准输出 会输出到当前目录的nohup.out 文件。即使关闭xshell 退出后,当前session依然继续运行。

1.2、 & (可交互)

& 语法格式:

command [arg…] &
1
说明:

能进行输入操作(比如输入命令、换行、打空格等),即 可进行交互 输入和输出的操作。
标准输出 保存到 nohup.out文件中。
但是 关闭客户端后,程序会就马上停止。
例如:

执行 sh test.sh & 脚本命令后 ,关闭 xshell,脚本程序也立刻停止。

1.3、nohup 和 & 一块使用(不挂断,可交互)

语法格式:

nohup command [arg…] &
1
说明:

能进行输入操作(比如输入命令、换行、打空格等),即 可进行交互 输入和输出的操作,
标准输出 保存到 nohup.out 中,
关闭客户端后命令仍然会运行。
例子:
执行 nohup sh test.sh & 命令后,能进行输入操作,标准输出 的日志写入到 nohup.out 文件,即使关闭xshell,退出当前session后,脚本命令依然继续运行。

输入输出问题已经解决了, 是不是就完美了? 其实还有一个问题没有解决, 请往下看!
二、 日志 的 重定向 >

上面提到的日志文件默认名称是 nohup.out ,如果修改日志文件的名称,则用到 重定向 ,符号是 > ,语法格式是

fileLog
1
说明:

是重定向的符号。
fileLog 是日志文件名称,最好是英文、数字。
此时, nohup、 & 、 > 三者一块使用的 语法格式 :

nohup command >fileLog &
1
示例:

nohup start.sh >aa.log &
1
说明:执行上面的命令后,可以进行输入,也能在后台运行,运行的日志输出到 aa.log 日志中。

三、错误信息的处理

nohup command >fileLog &
1
虽然解决输入输出,后台也能运行问题,但是还有一项是 错误信息 无法输出到 日志文件中,要解决这个问题,需要增加命令 2 > file 。

标准输出 和 错误信息 同时使用,语法格式如下:

fileLog1 2 >fileLog2
1
有人会疑问,2 是什么意思? 请往下看。

3.1、Linux 标准输入、输出、错误信息的符号

Linux 标准输入、输出、错误信息的符号:

0 表示 stdin (standard input) 标准信息输入 ;
1 表示 stdout (standard output) 标准信息输出 ;
2 表示 stderr (standard error) 错误信息 ;
/dev/null 表示空设备文件。 如果不想输出任何的日志时,使用此参数 。
再来回顾上面的示例:

fileLog1 2 >fileLog2
1
fileLog1 :即 1 >fileLog1,1是标准信息输出,是默认的,可以省略,fileLog1是 日志文件名字。

2 >fileLog2 :2 是错误信息,即将 错误信息 输出 到 fileLog2 文件中 。

到这时,明白 2 含义了吧!

3.2、错误信息 和 标准输出 输出在同一个文件中

如果想把 错误信息 和 标准输出 在同一个文件中 ,使用 2>&1 。 语法如下:

fileLog 2>&1
1
说明:

fileLog 表示 标准信息 输出到 fileLog 文件中;
2>&1 表示 把 2(错误信息) 重定向, 输出到 1(标准输出) 中 。
两者的共同使用,表示 把 2(错误信息) 、1(标准输出) 都输出到同一个文件(fileLog)中。

3.3、思考:不想输出日志信息怎么办 ?

提示:/dev/null 表示空设备文件。 如果不想输出任何的日志时,使用此参数 。

四、综合使用(推荐)

综上所述, 功能最全、推荐语法如下:

nohup command >fileLog 2>&1 &
1
示例:

nohup start.sh > mySysLog.log 2>&1 &
1
说明: 执行命令后,并且将 标准输出(1)、错误信息(2) 写入到 mySysLog.log 文件中。

五、知识扩展

5.1、不停止服务,直接清空nohup.out

如果脚本一直运行下去,nohup.out 日志会一直增长,日志但是硬盘容量有限,怎么把日志文件的大小减少 ?
注意,千万别直接删除日志文件,会造成服务无法输出日志,服务异常直接停止运行,这是最严重生产事故。

不停止服务,直接清空nohup.out文件有两种方法:

第1种:

cat /dev/null > nohup.out

第2种:

cp /dev/null nohup.out

5.2、只记录警告级别比较高的日志

输出的日志太多,nohup.out 增长特别快,对于不重要的日记,可以不记录,选择只记录警告级别比较高的日志。

只输出错误信息到日志文件,其它日志不输出

nohup ./program > /dev/null 2>log &

5.2、不想输出日志

不想输出日志,什么日志都不要,只要服务能正常运行就行了。

什么日志也不输出

nohup ./program > /dev/null 2>&1 &

使用overlayfs打造一个只读的不怕意外关机的树莓派Raspberry Pi

树莓派的本领就不多说了。但是在树莓派的应用场合,关机的时候还是显得尴尬,先不说执行 sudo halt 要么需要ssh上去,要么需要有键盘和显示器,更不要说,有的场景可能连网络和显示器都没有,真正的 headless。 但是如果不执行sudo halt直接关电源,那么有很大的概率会损坏SD卡上的文件系统,甚至损坏SD卡。

overlayfs是linux系统下的一种影子文件系统,它可以把真正的存储文件系统作为只读挂载,而把所有文件改动都存放在RAM中,关机或者重启就失效,真正的保护了存储文件系统。 下面就说一下我在树莓派中实施overlayfs的方法,其实很简单。

我参考了这个帖子中介绍的方法:

https://www.raspberrypi.org/forums/viewtopic.php?t=173063#p1151405

  1. 首先,禁用交换空间,毕竟树莓派里的交换空间也是占用RAM(tempfs)的,所以如果使用了overlayfs后,交换空间就显得没有意义了。

执行如下3条命令:

sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove

  1. 更新系统,保证系统为最新状态

sudo apt-get update
sudo apt-get upgrade

  1. 保存如下脚本为 overlayRoot.sh

注(2020-11-22):如下脚本已过时,最新脚本请前往链接【 http://wiki.psuter.ch/doku.php?id=solve_raspbian_sd_card_corruption_issues_with_read-only_mounted_root_partition#the_script 】

!/bin/sh

Read-only Root-FS for Raspian using overlayfs

Version 1.0

#

Created 2017 by Pascal Suter @ DALCO AG, Switzerland

to work on Raspian as custom init script

(raspbian does not use an initramfs on boot)

#

Modified 2017-Apr-21 by Tony McBeardsley

#

This program is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

#

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

#

You should have received a copy of the GNU General Public License

along with this program. If not, see

http://www.gnu.org/licenses/.

#
#

Tested with Raspbian mini, 2017-01-11

#

This script will mount the root filesystem read-only and overlay it with a temporary tempfs

which is read-write mounted. This is done using the overlayFS which is part of the linux kernel

since version 3.18.

when this script is in use, all changes made to anywhere in the root filesystem mount will be lost

upon reboot of the system. The SD card will only be accessed as read-only drive, which significantly

helps to prolong its life and prevent filesystem coruption in environments where the system is usually

not shut down properly

#

Install:

copy this script to /sbin/overlayRoot.sh and add “init=/sbin/overlayRoot.sh” to the cmdline.txt

file in the raspbian image’s boot partition.

I strongly recommend to disable swapping before using this. it will work with swap but that just does

not make sens as the swap file will be stored in the tempfs which again resides in the ram.

run these commands on the booted raspberry pi BEFORE you set the init=/sbin/overlayRoot.sh boot option:

sudo dphys-swapfile swapoff

sudo dphys-swapfile uninstall

sudo update-rc.d dphys-swapfile remove

#

To install software, run upgrades and do other changes to the raspberry setup, simply remove the init=

entry from the cmdline.txt file and reboot, make the changes, add the init= entry and reboot once more.

fail(){
echo -e “$1”
/bin/bash
}

Load overlay module

modprobe overlay
if [ $? -ne 0 ]; then
fail “ERROR: missing overlay kernel module”
fi

Mount /proc

mount -t proc proc /proc
if [ $? -ne 0 ]; then
fail “ERROR: could not mount proc”
fi

Create a writable fs on /mnt to then create our mountpoints

mount -t tmpfs inittemp /mnt
if [ $? -ne 0 ]; then
fail “ERROR: could not create a temporary filesystem to mount the base filesystems for overlayfs”
fi

Mount a tmpfs under /mnt/rw

mkdir /mnt/rw
mount -t tmpfs root-rw /mnt/rw
if [ $? -ne 0 ]; then
fail “ERROR: could not create tempfs for upper filesystem”
fi

Identify root fs device, PARTUUID, mount options and fs type

rootDev=blkid -o list | awk '$3 == "/" {print $1}'

Changed here(point to / ) in case the cmd above doesn’t work # By ChenYang 20171122

rootDev=/dev/mmcblk0p2
rootPARTUUID=awk '$2 == "/" {print $1}' /etc/fstab
rootMountOpt=awk '$2 == "/" {print $4}' /etc/fstab
rootFsType=awk '$2 == "/" {print $3}' /etc/fstab

Mount original root filesystem readonly under /mnt/lower

mkdir /mnt/lower
mount -t ${rootFsType} -o ${rootMountOpt},ro ${rootDev} /mnt/lower
if [ $? -ne 0 ]; then
fail “ERROR: could not ro-mount original root partition”
fi

Mount the overlay filesystem

mkdir /mnt/rw/upper
mkdir /mnt/rw/work
mkdir /mnt/newroot
mount -t overlay -o lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work overlayfs-root /mnt/newroot
if [ $? -ne 0 ]; then
fail “ERROR: could not mount overlayFS”
fi

Create mountpoints inside the new root filesystem-overlay

mkdir /mnt/newroot/ro
mkdir /mnt/newroot/rw

Remove root mount from fstab (this is already a non-permanent modification)

grep -v “$rootPARTUUID” /mnt/lower/etc/fstab > /mnt/newroot/etc/fstab
echo “#the original root mount has been removed by overlayRoot.sh” >> /mnt/newroot/etc/fstab
echo “#this is only a temporary modification, the original fstab” >> /mnt/newroot/etc/fstab
echo “#stored on the disk can be found in /ro/etc/fstab” >> /mnt/newroot/etc/fstab

Change to the new overlay root

cd /mnt/newroot
pivot_root . mnt
exec chroot . sh -c “$(cat <<END

# Move ro and rw mounts to the new root
mount --move /mnt/mnt/lower/ /ro
if [ $? -ne 0 ]; then
    echo "ERROR: could not move ro-root into newroot"
    /bin/bash
fi
mount --move /mnt/mnt/rw /rw
if [ $? -ne 0 ]; then
    echo "ERROR: could not move tempfs rw mount into newroot"
    /bin/bash
fi

# Unmount unneeded mounts so we can unmout the old readonly root
umount /mnt/mnt
umount /mnt/proc
umount /mnt/dev
umount /mnt

# Continue with regular init
exec /sbin/init

END
)”

注意,我的脚本和帖子里面的有些不同,我把

rootDev=blkid -o list | awk '$3 == "/" {print $1}'

改成了

rootDev=/dev/mmcblk0p2

不改的话,我这里overlayRoot.sh会运行失败

(20180503更新)另外需要注意,如果在Windows下编辑overlayRoot.sh文件,需要保存为Unix文本文档格式,即行结束符为单个LF字符,而不是Windows风格的CR+LR两个字符。否则你可能会看到如下错误:

—[ end Kernel panic – not syncing: Requested init /sbin/overlayRoot.sh failed (error -2).

  1. 将脚本拷贝到 /sbin/overlayRoot.sh

sudo cp overlayRoot.sh /sbin/overlayRoot.sh
sudo chmod a+x /sbin/overlayRoot.sh

  1. 修改 cmdline.txt 文件,在行尾加上 “init=/sbin/overlayRoot.sh”,如下是我的 /boot/cmdline.txt 文件的内容

pi@raspberrypi:~ $ cat /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=0e82c2e4-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait init=/sbin/overlayRoot.sh

  1. 为了保证整个SD卡都是只读,将 /boot 分区也修改为只读, 修改 fstab 文件,把/boot 对应的行改为ro,我的/etc/fstab文件内容如下

pi@raspberrypi:~ $ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=0e82c2e4-01 /boot vfat defaults,ro 0 2
PARTUUID=0e82c2e4-02 / ext4 defaults,noatime 0 1

  1. 到这里 sudo reboot 重启,重启后,文件系统就处于影子系统的保护之下了,所有对于文件系统的改动,在重启后都将恢复原状。 用mount命令可以确认overlayfs的正常工作。

root-rw on /rw type tmpfs (rw,relatime)
/dev/mmcblk0p2 on /ro type ext4 (ro,noatime,data=ordered)
overlayfs-root on / type overlay (rw,relatime,lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,size=470160k,nr_inodes=117540,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=25,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
sunrpc on /run/rpc_pipefs type rpc_pipefs (rw,relatime)
mqueue on /dev/mqueue type mqueue (rw,relatime)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/mmcblk0p1 on /boot type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=94952k,mode=700,uid=1000,gid=1000)

原来的根文件系统 /dev/mmcblk0p2 改为挂载在 /ro ,并且是只读;/boot 也挂载为只读;而 / 的 type 变成了overlay。

好了,直接拔电试试看吧。事实上你可以反复尝试不正常关机,都不会有问题。

  1. 以后如果想禁用overlayfs,可以修改 cmdline.txt 把 “init=/sbin/overlayRoot.sh” 删掉,重启即可。 当然修改前要先把 /boot remount 成可写状态。

更新系统等操作都需要先禁用overlayfs后再执行。

  1. 如果临时想修改原 /boot 以及根文件系统的内容可以如下命令remount

要remount /boot为可写

pi@raspberrypi:~ $ sudo mount -o remount,rw /boot

原来的根文件系统在overlayfs下是挂载在 /ro 的,要remount的话

pi@raspberrypi:~ $ sudo mount -o remount,rw /ro

注意,remount文件系统为可写后,要重启和关机需要使用sudo reboot或者sudo halt,不可以强行非正常关机,以免损坏文件系统。

PS. 网上有人报告,如果在不接显示器的情况下(即 headless),如上脚本会运行失败,但是我不接显示器时并没有遇到此问题 。

PS2. 网上有另外一个脚本,链接如下

https://gist.githubusercontent.com/niun/34c945d70753fc9e2cc7/raw/3d60338cd8d8daf740692f426a5a1ec17839d613/root-ro

使用了 update-initramfs 的方式,我在官方系统中可以使用,但是在修改了内核的系统中,运行失败。

【20180717后记】

— 如果开启了overlay以后,root分区的所有变动重启后都会丢失,如果要保存数据,可以缩小root分区后另外建立一个分区,使用FAT32,并mount为rw, sync, flush,用来保存数据,另外最好使用f2fs分区格式,据说f2fs就是针对SD卡之类的存储优化设计的。当然保存数据的频率不要太高,否则异常关机仍有可能会损坏SD卡,就失去使用overlay的意义了。 如果保存数据的频率很高,比如log,可以考虑保存到外接U盘。

— 也有人把 /boot 挂载为rw并临时存放数据,我认为那是不可取的,因为 /boot 里面存放的是启动设置信息以及内核等。

— 网上也有人修改脚本,(https://github.com/jacobalberty/root-ro),使得可以短路某GPIO后启动系统就可写,断开后启动就只读。这是个好主意,有空研究一下。

【20180718更新】 另写了一篇来说明上面这一条的方法。 https://blog.csdn.net/zhufu86/article/details/81100710

【20180720更新】 为了方便识别当前系统是不是在overlayfs模式下,我在 .bashrc 的结尾加上如下几行(当然必须在非overlayfs下修改,否则修改内容不会保存),这样如果是在overlayfs模式下,命令提示行的前面会加上“[OVL]”

find_overlay=mount | grep overlay

if [ ${#find_overlay} -gt 0 ]; then
PS1=”[OVL] $PS1″
fi
【2020-11-22更新】最近留意到raspi-config里面已经有了打开Overlay FS的功能,但是我不是很清楚其使用的方案,大概了解了一下,似乎需要动内核相关文件(如果我的认知有误请指正),这个是我不喜欢的。因为有时如果使用定制化内核,就可能和这种方案有冲突。 同时,我发现本文中方案的原作者已经更新了脚本 overlayRoot.sh ,请前往链接【 http://wiki.psuter.ch/doku.php?id=solve_raspbian_sd_card_corruption_issues_with_read-only_mounted_root_partition 】,他解决了之前自动搜索fstab文件中相关分区信息失败的问题。

https://blog.csdn.net/farmanlinuxer/article/details/96880345

树莓派RaspberryPiB+Raspbian-jessie制作只读系统的python3脚本

python反爬虫模块fake_useragent

Python3 fake_useragent 模块的使用和报错解决方案

https://blog.csdn.net/yilovexing/article/details/89044980?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-89044980-blog-105354439.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-89044980-blog-105354439.pc_relevant_default&utm_relevant_index=1

在使用 Python 做爬虫的时候,我们需要伪装头部信息骗过网站的防爬策略,Python 中的第三方模块 fake_useragent 就很好的解决了这个问题,它将给我们返回一个随机封装了好的头部信息,我们直接使用即可

fake_useragent 的使用

安装 fake_useragent

pip install fake_useragent
1
示例:

from fake_useragent import UserAgent

实例化 UserAgent 类

ua = UserAgent()

对应浏览器的头部信息

print(ua.ie)
print(ua.opera)
print(ua.chrome)
print(ua.firefox)
print(ua.safari)

随机返回头部信息,推荐使用

print(ua.random)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
运行结果:

(adnice) adnice:Downloads zhangyi$ python3 fake.py
Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.1; SLCC1; .NET CLR 1.1.4322)
Opera/9.80 (Windows NT 6.1; U; fi) Presto/2.7.62 Version/11.00
Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1500.55 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:23.0) Gecko/20131011 Firefox/23.0
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27
Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2117.157 Safari/537.36
1
2
3
4
5
6
7
fake_useragent 报错及解决方案

报错信息:

socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “d:\programdata\anaconda3\lib\site-packages\fake_useragent\utils.py”, lin
e 166, in load
verify_ssl=verify_ssl,
File “d:\programdata\anaconda3\lib\site-packages\fake_useragent\utils.py”, lin
e 122, in get_browser_versions
verify_ssl=verify_ssl,
File “d:\programdata\anaconda3\lib\site-packages\fake_useragent\utils.py”, lin
e 84, in get
raise FakeUserAgentError(‘Maximum amount of retries reached’)
fake_useragent.errors.FakeUserAgentError: Maximum amount of retries reached
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
首先找出关键报错信息:

fake_useragent.errors.FakeUserAgentError: Maximum amount of retries reached
1
大概意思是:这个模块尝试请求一个东西已达到最大重试次数

打开这个模块的源码进行查看发现这个库会引用在线资源,所以这个模块是进行几次尝试请求一个网站的 Json 数据,但是因为各种原因请求超时,所以就会报这个错误

fake_useragent\settings.py

– coding: utf-8 –

from future import absolute_import, unicode_literals

import os
import tempfile

version = ‘0.1.11’

DB = os.path.join(
tempfile.gettempdir(),
‘fake_useragent_{version}.json’.format(
version=version,
),
)

CACHE_SERVER = ‘https://fake-useragent.herokuapp.com/browsers/{version}’.format(
version=version,
)

BROWSERS_STATS_PAGE = ‘https://www.w3schools.com/browsers/default.asp’

BROWSER_BASE_PAGE = ‘http://useragentstring.com/pages/useragentstring.php?name={browser}’ # noqa

BROWSERS_COUNT_LIMIT = 50

REPLACEMENTS = {
‘ ‘: ”,
‘_’: ”,
}

SHORTCUTS = {
‘internet explorer’: ‘internetexplorer’,
‘ie’: ‘internetexplorer’,
‘msie’: ‘internetexplorer’,
‘edge’: ‘internetexplorer’,
‘google’: ‘chrome’,
‘googlechrome’: ‘chrome’,
‘ff’: ‘firefox’,
}

OVERRIDES = {
‘Edge/IE’: ‘Internet Explorer’,
‘IE/Edge’: ‘Internet Explorer’,
}

HTTP_TIMEOUT = 5

HTTP_RETRIES = 2

HTTP_DELAY = 0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
解决方案:

首先第一步要进行更新 fake_useragent

pip install –upgrade fake_useragent
1

  1. 在实例化的时候指定一些参数

禁用服务器缓存

ua = UserAgent(use_cache_server=False)
1
不缓存数据

ua = UserAgent(cache=False)
1
忽略ssl验证

ua = UserAgent(verify_ssl=False)
1
一般的话,通过上述解决方案都能解决了,但是我就比较悲催了,还是没解决…

  1. 使用临时 Json 文件

在 fake_useragent\settings.py 发现了几个 URL,其中有一些是打不开的,所以,我们将能打开的 URL 的 Json 文件保存在本地

wget https://fake-useragent.herokuapp.com/browsers/0.1.11
1
这时我们就会得到一个 0.1.11 的文件,将文件名改为 fake_useragent_0.1.11.json

mv 0.1.11 fake_useragent_0.1.11.json
1
然后找到我们的临时文件目录(每个系统都不一样,例如 Ubuntu 在 /tmp 下)

(edison) adnice:T zhangyi$ python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:52:21)
[Clang 6.0 (clang-600.0.57)] on darwin
Type “help”, “copyright”, “credits” or “license” for more information.

import tempfile
tempfile.gettempdir()
‘/var/folders/6_/p67xz49j5wd5lzx7s2cz1cdr0000gn/T’

1
2
3
4
5
6
7
8
最后将文件拷贝到临时目录中即可

cp fake_useragent_0.1.11.json /var/folders/6_/p67xz49j5wd5lzx7s2cz1cdr0000gn/T/
1
当我们再次实例化 UserAgent 的时候,就会先读取本地的临时文件,这样实例化的时候就不会报错了

参考文章:https://blog.csdn.net/huiyanshizhu/article/details/84952093

python 监控网站是否正常工作

#-*- coding: utf-8 -*
import requests
from lxml import etree

#请求头和目标网址
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'
}
##url = 'https://www.jianshu.com/u/472a595d244c'
url = 'http://www.mixdiy.com'
#第二种写法的 xpath
#获取所有 li标签
xpath_items = '//body[@class="home blog wp-custom-logo wp-embed-responsive"]/div'
#对每个 li标签再提取
xpath_link = './footer/div/a/@href'
xpath_title = './footer/div/a/text()'
##xpath_comment_num = './/div[@class="meta"]/a[2]/text()'
##xpath_heart_num = './/div[@class="meta"]/span/text()'

#获取和解析网页
r = requests.get(url, headers=headers)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)

#获取所有的文章标签
items = dom.xpath(xpath_items)

#分别对每一个文章标签进行操作 将每篇文章的链接 标题 评论数 点赞数放到一个字典里
data = []
for article in items:
    t = {}
    t['link'] = article.xpath(xpath_link)[0]
    t['title'] = article.xpath(xpath_title)[0]
    #comment_num对应的标签里有两个文本标签 用 join方法将两个文本拼接起来
    #strip()方法去除换行和空格
##    t['comment_num'] = ''.join(article.xpath(xpath_comment_num)).strip()
##    t['heart_num'] = article.xpath(xpath_heart_num)[0].strip()
    data.append(t)

#打印结果
print(data[0]['link'])

if 'mixdiy.com' in data[0]['link']:
    print('online')
else:
    print('offline')

python网络爬虫

https://www.jianshu.com/p/ff37a8524e72

一、前言

上一节我们讲了怎么批量下载壁纸,虽然爬虫的代码很简单,但是却有一个很重要的问题,那就是 xpath路径应该怎么写。

这个问题往往会被我们忽略,但 xpath路径的写法是很重要的。不同的 xpath路径写法会后续爬取代码会产生很大影响,而且不同的 xpath写法的稳定性也不同,能不能写出优雅稳定的代码就要看 xpath写得好不好了。

下面我们来讲讲为什么 xpath的写法这么重要

二、为什么 xpath写法很重要

我们拿几个例子来讲讲不同 xpath写法对代码的影响,以我的个人主页作为解析对象:

python爬虫猫的个人主页

现在的需求是要爬取我个人主页里的文章列表,包括文章的链接、标题、访问量、评论数和点赞数量

个人主页

爬之前我们先分析一下

1、爬什么:文章链接文章的链接、标题、评论数和点赞数量

2、怎么爬:requests请求网页、xpath解析网页

接下来正式开始爬取:

第一步:分析网页,写出图片的 xpath路径

第二步:用 requests库获取网页

第三步:使用 lxml库解析网页

第四步:把爬取到的信息保存下来

我们一步一步来,首先分析网页,写出 xpath

按 F12进入开发者模式,找到文章列表所在的标签

example-2.png

可以看到,文章列表是一个 ul标签,ul标签下的每一个 li标签分别代表一篇文章。

我们要爬的信息都在 class=”content”的 div标签下:

  • 文章链接是第一个 a标签的 herf属性值
  • 文章标题是第一个 a标签的文本属性的值
  • 文章的评论数是 class=”meta”的 div标签下的第二个 a标签下的文本值
  • 文章点赞数量是 class=”meta”的 div标签下的 span标签下的文本值

这时候 xpath有很多种写法,我写出其中的两种,一好一坏,大家可以试着判断一下哪个好哪个坏

第一种写法:

xpath_link = '//ul[@class="note-list"]/li/div/a/@href'
xpath_title = '//ul[@class="note-list"]/li/div/a/text()'
xpath_comment_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/a[2]/text()'
xpath_heart_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/span/text()'

第二种写法:

#获取所有 li标签
xpath_items = '//ul[@class="note-list"]/li'
#对每个 li标签再提取
xpath_link = './div/a/@href'
xpath_title = './div/a/text()'
xpath_comment_num = './/div[@class="meta"]/a[2]/text()'
xpath_heart_num = './/div[@class="meta"]/span/text()'

写好 xpath之后,我们开始第二步,获取网页

获取简书的网页如果我们还像之前那样直接请求的话,就会得到一个 403错误,这是因为没有设置请求头。

加上请求头就能解决了[]( ̄▽ ̄)*

第一种 xpath写法对应的代码:

#-*- coding: utf-8 -*
import requests
from lxml import etree


#请求头和目标网址
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'
}
url = 'https://www.jianshu.com/u/472a595d244c'

#第一种写法的 xpath
xpath_link = '//ul[@class="note-list"]/li/div/a/@href'
xpath_title = '//ul[@class="note-list"]/li/div/a/text()'
xpath_comment_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/a[2]/text()'
xpath_heart_num = '//ul[@class="note-list"]/li/div/div[@class="meta"]/span/text()'

#获取和解析网页
r = requests.get(url, headers=headers)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)

#所有的 链接 标题 评论数 点赞数
links = dom.xpath(xpath_link)
titles = dom.xpath(xpath_title)
comment_nums = dom.xpath(xpath_comment_num)
heart_nums = dom.xpath(xpath_heart_num)

#将每篇文章的链接 标题 评论数 点赞数放到一个字典里
data = []
for i in range(len(links)):
    t = {}
    t['link'] = links[i]
    t['title'] = titles[i]
    t['comment_num'] = comment_nums[i].strip()
    t['heart_num'] = heart_nums[i].strip()
    data.append(t)

#打印结果
for t in data:
    print(t)



运行结果如下:

example-3

可以看到,第一篇和第三篇的 comment_num 没有获取到

第二种 xpath写法对应的代码:

#-*- coding: utf-8 -*
import requests
from lxml import etree


#请求头和目标网址
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36'
}
url = 'https://www.jianshu.com/u/472a595d244c'

#第二种写法的 xpath
#获取所有 li标签
xpath_items = '//ul[@class="note-list"]/li'
#对每个 li标签再提取
xpath_link = './div/a/@href'
xpath_title = './div/a/text()'
xpath_comment_num = './/div[@class="meta"]/a[2]/text()'
xpath_heart_num = './/div[@class="meta"]/span/text()'


#获取和解析网页
r = requests.get(url, headers=headers)
r.encoding = r.apparent_encoding
dom = etree.HTML(r.text)

#获取所有的文章标签
items = dom.xpath(xpath_items)

#分别对每一个文章标签进行操作 将每篇文章的链接 标题 评论数 点赞数放到一个字典里
data = []
for article in items:
    t = {}
    t['link'] = article.xpath(xpath_link)[0]
    t['title'] = article.xpath(xpath_title)[0]
    #comment_num对应的标签里有两个文本标签 用 join方法将两个文本拼接起来
    #strip()方法去除换行和空格
    t['comment_num'] = ''.join(article.xpath(xpath_comment_num)).strip()
    t['heart_num'] = article.xpath(xpath_heart_num)[0].strip()
    data.append(t)

#打印结果
for t in data:
    print(t)



运行结果:

example-4

这里 comment_num成功获得了

仅仅从获取的结果来看,我们就可以判断第二种 xpath写法更好。

为什么第二种写法更好呢?

因为第二种方法把每一篇文章看作一个对象,这样后续的处理都是以对象为基本单位,对数据进行处理的时候过程更加清晰。

而第一种写法把链接、标题、评论数和点赞数量这四个分别用列表存储,这样虽然同样可以获得结果,但是再进行数据处理的时候就需要考虑怎么才能不破坏四个变量之间的一一对应关系。

用第二种方法就没有这个问题,因为在处理数据的时候它们都被看作同一个对象的组成部分,这本身就蕴含着蕴含着一种关系。

现在问题来了,平时我们在爬取数据的时候,怎么才能判断哪些数据是同一个对象呢?

这个其实很简单,在我们分析需求的时候就已经知道了,我们所需要数据的一个完整组合就是一个对象。

比如在本文的例子里,我们要爬取链接、标题、评论数和点赞数量,那么{链接,标题,评论数,点赞数量}就是一个对象。。

rc.local 使用python注意事项

在rc.local中使用python程序,一个注意事项是,加入在rc.local中如需sudo 运行python,则python的导入模块也需要用sudo install,否则会出现找不到模块的错误。

备份wordpress经验总结

wordpress网站备份总结

1、压缩/var/www/html目录

2、如果压缩文件很大则分割后再传输

3、在wordpress后台使用导出工具导出xml备份文件

4、将html目录压缩文件和导出的xml文件拷贝到新站

5、使用cat组合分割的压缩文件并解压到html目录下(解压前删除html下的所有文件)

6、创建wordpress数据库

7、访问站点并进入wordpress后台导入备份的xml文件

注:

前提条件是在新的系统上已经配置好环境(包括php、sql)

如何修复WordPress图片裁剪错误

我们现在知道错误的样子。让我们进一步了解如何修复图像裁剪错误。

作为故障排除的第一步,我们检查服务器的PHP版本以及GD库。如果缺少GD库,我们安装它。但是,GD安装步骤因服务器类型而异。

对于RedHat/CentOS主机,我们运行命令

yum install php-gd

或者,如果是Ubuntu服务器,GD安装使用

apt-get install php-gd

在这里,我们还要确保WordPress软件包的版本与主机的PHP版本相匹配。

最后,要制作新安装的GD库,需要重启web服务器。我们在服务器中通过

/etc/init.d/httpd restart

修复错误后,在“媒体库”中,用户可以选择图像并“插入文章”,完美解决问题。